ScrollViewExtend_无限重复循环——ScrollView(转)
//*****************************-》 基类 循环列表 《-**************************** //author kim //初始化: // Init(callBackFunc) //刷新整个列表(首次调用和数量变化时调用): // ShowList(int = 数量) //刷新单个项: // UpdateCell(int = 索引) //刷新列表数据(无数量变化时调用): // UpdateList() //回调: //Func(GameObject = Cell, int = Index) //刷新列表 using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; using System.Collections; using UnityEngine.EventSystems; using System; namespace CircularScrollView { public class UIUtils { public static void SetActive(GameObject obj, bool isActive) { if (obj != null) { obj.SetActive(isActive); } } } public enum e_Direction { Horizontal, Vertical } public class UICircularScrollView : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler { public GameObject m_PointingFirstArrow; public GameObject m_PointingEndArrow; public e_Direction m_Direction = e_Direction.Horizontal; public bool m_IsShowArrow = true; public int m_Row = 1; public float m_Spacing = 0f; //间距 public GameObject m_CellGameObject; //指定的cell protected Action<GameObject, int> m_FuncCallBackFunc; protected Action<GameObject, int> m_FuncOnClickCallBack; protected Action<int, bool, GameObject> m_FuncOnButtonClickCallBack; protected RectTransform rectTrans; protected float m_PlaneWidth; protected float m_PlaneHeight; protected float m_ContentWidth; protected float m_ContentHeight; protected float m_CellObjectWidth; protected float m_CellObjectHeight; protected GameObject m_Content; protected RectTransform m_ContentRectTrans; private bool m_isInited = false; //记录 物体的坐标 和 物体 protected struct CellInfo { public Vector3 pos; public GameObject obj; }; protected CellInfo[] m_CellInfos; protected bool m_IsInited = false; protected ScrollRect m_ScrollRect; protected int m_MaxCount = -1; //列表数量 protected int m_MinIndex = -1; protected int m_MaxIndex = -1; protected bool m_IsClearList = false; //是否清空列表 public virtual void Init(Action<GameObject, int> callBack) { Init(callBack, null); } public virtual void Init(Action<GameObject, int> callBack, Action<GameObject, int> onClickCallBack, Action<int, bool, GameObject> onButtonClickCallBack) { if (onButtonClickCallBack != null) { m_FuncOnButtonClickCallBack = onButtonClickCallBack; } Init(callBack, onClickCallBack); } public virtual void Init(Action<GameObject, int> callBack, Action<GameObject, int> onClickCallBack) { DisposeAll(); m_FuncCallBackFunc = callBack; if (onClickCallBack != null) { m_FuncOnClickCallBack = onClickCallBack; } if (m_isInited) return; m_Content = this.GetComponent<ScrollRect>().content.gameObject; if (m_CellGameObject == null) { m_CellGameObject = m_Content.transform.GetChild(0).gameObject; } /* Cell 处理 */ //m_CellGameObject.transform.SetParent(m_Content.transform.parent, false); SetPoolsObj(m_CellGameObject); RectTransform cellRectTrans = m_CellGameObject.GetComponent<RectTransform>(); cellRectTrans.pivot = new Vector2(0f, 1f); CheckAnchor(cellRectTrans); cellRectTrans.anchoredPosition = Vector2.zero; //记录 Cell 信息 m_CellObjectHeight = cellRectTrans.rect.height; m_CellObjectWidth = cellRectTrans.rect.width; //记录 Plane 信息 rectTrans = GetComponent<RectTransform>(); Rect planeRect = rectTrans.rect; m_PlaneHeight = planeRect.height; m_PlaneWidth = planeRect.width; //记录 Content 信息 m_ContentRectTrans = m_Content.GetComponent<RectTransform>(); Rect contentRect = m_ContentRectTrans.rect; m_ContentHeight = contentRect.height; m_ContentWidth = contentRect.width; m_ContentRectTrans.pivot = new Vector2(0f, 1f); //m_ContentRectTrans.sizeDelta = new Vector2 (planeRect.width, planeRect.height); //m_ContentRectTrans.anchoredPosition = Vector2.zero; CheckAnchor(m_ContentRectTrans); m_ScrollRect = this.GetComponent<ScrollRect>(); m_ScrollRect.onValueChanged.RemoveAllListeners(); //添加滑动事件 m_ScrollRect.onValueChanged.AddListener(delegate (Vector2 value) { ScrollRectListener(value); }); if (m_PointingFirstArrow != null || m_PointingEndArrow != null) { m_ScrollRect.onValueChanged.AddListener(delegate (Vector2 value) { OnDragListener(value); }); OnDragListener(Vector2.zero); } //InitScrollBarGameObject(); // 废弃 m_isInited = true; } //检查 Anchor 是否正确 private void CheckAnchor(RectTransform rectTrans) { if(m_Direction == e_Direction.Vertical) { if (!((rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(0, 1)) || (rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(1, 1)))) { rectTrans.anchorMin = new Vector2(0, 1); rectTrans.anchorMax = new Vector2(1, 1); } } else { if (!((rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(0, 1)) || (rectTrans.anchorMin == new Vector2(0, 0) && rectTrans.anchorMax == new Vector2(0, 1)))) { rectTrans.anchorMin = new Vector2(0, 0); rectTrans.anchorMax = new Vector2(0, 1); } } } //实时刷新列表时用 public virtual void UpdateList() { for (int i = 0, length = m_CellInfos.Length; i < length; i++) { CellInfo cellInfo = m_CellInfos[i]; if (cellInfo.obj != null) { float rangePos = m_Direction == e_Direction.Vertical ? cellInfo.pos.y : cellInfo.pos.x; if (!IsOutRange(rangePos)) { Func(m_FuncCallBackFunc, cellInfo.obj, true); } } } } //刷新某一项 public void UpdateCell(int index) { CellInfo cellInfo = m_CellInfos[index - 1]; if (cellInfo.obj != null) { float rangePos = m_Direction == e_Direction.Vertical ? cellInfo.pos.y : cellInfo.pos.x; if (!IsOutRange(rangePos)) { Func(m_FuncCallBackFunc, cellInfo.obj); } } } public virtual void ShowList(string numStr) { } public virtual void ShowList(int num) { m_MinIndex = -1; m_MaxIndex = -1; //-> 计算 Content 尺寸 if(m_Direction == e_Direction.Vertical) { float contentSize = (m_Spacing + m_CellObjectHeight) * Mathf.CeilToInt((float)num / m_Row); m_ContentHeight = contentSize; m_ContentWidth = m_ContentRectTrans.sizeDelta.x; contentSize = contentSize < rectTrans.rect.height ? rectTrans.rect.height : contentSize; m_ContentRectTrans.sizeDelta = new Vector2(m_ContentWidth, contentSize); if (num != m_MaxCount) { m_ContentRectTrans.anchoredPosition = new Vector2(m_ContentRectTrans.anchoredPosition.x, 0); } } else { float contentSize = (m_Spacing + m_CellObjectWidth) * Mathf.CeilToInt((float)num / m_Row); m_ContentWidth = contentSize; m_ContentHeight = m_ContentRectTrans.sizeDelta.x; contentSize = contentSize < rectTrans.rect.width ? rectTrans.rect.width : contentSize; m_ContentRectTrans.sizeDelta = new Vector2(contentSize, m_ContentHeight); if (num != m_MaxCount) { m_ContentRectTrans.anchoredPosition = new Vector2(0, m_ContentRectTrans.anchoredPosition.y); } } //-> 计算 开始索引 int lastEndIndex = 0; //-> 过多的物体 扔到对象池 ( 首次调 ShowList函数时 则无效 ) if (m_IsInited) { lastEndIndex = num - m_MaxCount > 0 ? m_MaxCount : num; lastEndIndex = m_IsClearList ? 0 : lastEndIndex; int count = m_IsClearList ? m_CellInfos.Length : m_MaxCount; for (int i = lastEndIndex; i < count; i++) { if (m_CellInfos[i].obj != null) { SetPoolsObj(m_CellInfos[i].obj); m_CellInfos[i].obj = null; } } } //-> 以下四行代码 在for循环所用 CellInfo[] tempCellInfos = m_CellInfos; m_CellInfos = new CellInfo[num]; //-> 1: 计算 每个Cell坐标并存储 2: 显示范围内的 Cell for (int i = 0; i < num; i++) { // * -> 存储 已有的数据 ( 首次调 ShowList函数时 则无效 ) if (m_MaxCount != -1 && i < lastEndIndex) { CellInfo tempCellInfo = tempCellInfos[i]; //-> 计算是否超出范围 float rPos = m_Direction == e_Direction.Vertical ? tempCellInfo.pos.y : tempCellInfo.pos.x; if (!IsOutRange(rPos)) { //-> 记录显示范围中的 首位index 和 末尾index m_MinIndex = m_MinIndex == -1 ? i : m_MinIndex; //首位index m_MaxIndex = i; // 末尾index if (tempCellInfo.obj == null) { tempCellInfo.obj = GetPoolsObj(); } tempCellInfo.obj.transform.GetComponent<RectTransform>().anchoredPosition = tempCellInfo.pos; tempCellInfo.obj.name = i.ToString(); tempCellInfo.obj.SetActive(true); Func(m_FuncCallBackFunc, tempCellInfo.obj); } else { SetPoolsObj(tempCellInfo.obj); tempCellInfo.obj = null; } m_CellInfos[i] = tempCellInfo; continue; } CellInfo cellInfo = new CellInfo(); float pos = 0; //坐标( isVertical ? 记录Y : 记录X ) float rowPos = 0; //计算每排里面的cell 坐标 // * -> 计算每个Cell坐标 if(m_Direction == e_Direction.Vertical) { pos = m_CellObjectHeight * Mathf.FloorToInt(i / m_Row) + m_Spacing * Mathf.FloorToInt(i / m_Row); rowPos = m_CellObjectWidth * (i % m_Row) + m_Spacing * (i % m_Row); cellInfo.pos = new Vector3(rowPos, -pos, 0); } else { pos = m_CellObjectWidth * Mathf.FloorToInt(i / m_Row) + m_Spacing * Mathf.FloorToInt(i / m_Row); rowPos = m_CellObjectHeight * (i % m_Row) + m_Spacing * (i % m_Row); cellInfo.pos = new Vector3(pos, -rowPos, 0); } //-> 计算是否超出范围 float cellPos = m_Direction == e_Direction.Vertical ? cellInfo.pos.y : cellInfo.pos.x; if (IsOutRange(cellPos)) { cellInfo.obj = null; m_CellInfos[i] = cellInfo; continue; } //-> 记录显示范围中的 首位index 和 末尾index m_MinIndex = m_MinIndex == -1 ? i : m_MinIndex; //首位index m_MaxIndex = i; // 末尾index //-> 取或创建 Cell GameObject cell = GetPoolsObj(); cell.transform.GetComponent<RectTransform>().anchoredPosition = cellInfo.pos; cell.gameObject.name = i.ToString(); //-> 存数据 cellInfo.obj = cell; m_CellInfos[i] = cellInfo; //-> 回调 函数 Func(m_FuncCallBackFunc, cell); } m_MaxCount = num; m_IsInited = true; OnDragListener(Vector2.zero); } // 更新滚动区域的大小 public void UpdateSize() { Rect rect = GetComponent<RectTransform>().rect; m_PlaneHeight = rect.height; m_PlaneWidth = rect.width; } //滑动事件 protected virtual void ScrollRectListener(Vector2 value) { UpdateCheck(); } private void UpdateCheck() { if (m_CellInfos == null) return; //检查超出范围 for (int i = 0, length = m_CellInfos.Length; i < length; i++) { CellInfo cellInfo = m_CellInfos[i]; GameObject obj = cellInfo.obj; Vector3 pos = cellInfo.pos; float rangePos = m_Direction == e_Direction.Vertical ? pos.y : pos.x; //判断是否超出显示范围 if (IsOutRange(rangePos)) { //把超出范围的cell 扔进 poolsObj里 if (obj != null) { SetPoolsObj(obj); m_CellInfos[i].obj = null; } } else { if (obj == null) { //优先从 poolsObj中 取出 (poolsObj为空则返回 实例化的cell) GameObject cell = GetPoolsObj(); cell.transform.localPosition = pos; cell.gameObject.name = i.ToString(); m_CellInfos[i].obj = cell; Func(m_FuncCallBackFunc, cell); } } } } //判断是否超出显示范围 protected bool IsOutRange(float pos) { Vector3 listP = m_ContentRectTrans.anchoredPosition; if(m_Direction == e_Direction.Vertical) { if (pos + listP.y > m_CellObjectHeight || pos + listP.y < -rectTrans.rect.height) { return true; } } else { if (pos + listP.x < -m_CellObjectWidth || pos + listP.x > rectTrans.rect.width) { return true; } } return false; } //对象池 机制 (存入, 取出) cell protected Stack<GameObject> poolsObj = new Stack<GameObject>(); //取出 cell protected virtual GameObject GetPoolsObj() { GameObject cell = null; if (poolsObj.Count > 0) { cell = poolsObj.Pop(); } if (cell == null) { cell = Instantiate(m_CellGameObject) as GameObject; } cell.transform.SetParent(m_Content.transform); cell.transform.localScale = Vector3.one; UIUtils.SetActive(cell, true); return cell; } //存入 cell protected virtual void SetPoolsObj(GameObject cell) { if (cell != null) { poolsObj.Push(cell); UIUtils.SetActive(cell, false); } } //回调 protected void Func(Action<GameObject, int> func, GameObject selectObject, bool isUpdate = false) { int num = int.Parse(selectObject.name) + 1; if (func != null) { func(selectObject, num); } } public void DisposeAll() { if (m_FuncCallBackFunc != null) { m_FuncCallBackFunc = null; } if (m_FuncOnClickCallBack != null) { m_FuncOnClickCallBack = null; } } protected void OnDestroy() { DisposeAll(); } public virtual void OnClickCell(GameObject cell) { } //-> ExpandCircularScrollView 函数 public virtual void OnClickExpand(int index) { } //-> FlipCircularScrollView 函数 public virtual void SetToPageIndex(int index) { } public virtual void OnBeginDrag(PointerEventData eventData) { } public void OnDrag(PointerEventData eventData) { } public virtual void OnEndDrag(PointerEventData eventData) { } protected void OnDragListener(Vector2 value) { float normalizedPos = m_Direction == e_Direction.Vertical ? m_ScrollRect.verticalNormalizedPosition : m_ScrollRect.horizontalNormalizedPosition; if(m_Direction == e_Direction.Vertical) { if (m_ContentHeight - rectTrans.rect.height < 10) { UIUtils.SetActive(m_PointingFirstArrow, false); UIUtils.SetActive(m_PointingEndArrow, false); return; } } else { if (m_ContentWidth - rectTrans.rect.width < 10) { UIUtils.SetActive(m_PointingFirstArrow, false); UIUtils.SetActive(m_PointingEndArrow, false); return; } } if (normalizedPos >= 0.9) { UIUtils.SetActive(m_PointingFirstArrow, false); UIUtils.SetActive(m_PointingEndArrow, true); } else if (normalizedPos <= 0.1) { UIUtils.SetActive(m_PointingFirstArrow, true); UIUtils.SetActive(m_PointingEndArrow, false); } else { UIUtils.SetActive(m_PointingFirstArrow, true); UIUtils.SetActive(m_PointingEndArrow, true); } } } }
------------------------------------------------------------
//*****************************-》 可收展 循环列表 《-**************************** //author: Kim //初始化: // Init(CallBack) //不需要 回调Cell点击函数时用此 Init() // Init(CallBack, OnClickCallBack) //需要回调 Cell点击函数时用此 Init() //刷新列表: // ShowList(数量格式: string = "5|5|6") //回调: //Func(GameObject = 收展按钮, GameObject = Cell, int = 收展按钮索引 Index, int = 子cell索引) //OnClickCell(GameObject = Cell, int = Index) //点击Cell using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace CircularScrollView { public class ExpandCircularScrollView : UICircularScrollView { public GameObject m_ExpandButton; public float m_BackgroundMargin; public bool m_IsExpand = false; private float m_ExpandButtonX; private float m_ExpandButtonY; private float m_ExpandButtonWidth; private float m_ExpandButtonHeight; private Vector2 m_BackgroundOriginSize; //展开信息 struct ExpandInfo { public GameObject button; public bool isExpand; public CellInfo[] cellInfos; public float size; public int cellCount; } private ExpandInfo[] m_ExpandInfos = null; private Dictionary<GameObject, bool> m_IsAddedListener = new Dictionary<GameObject, bool>(); //用于 判断是否重复添加 点击事件 private new Action<GameObject, GameObject, int, int> m_FuncCallBackFunc; protected new Action<GameObject, GameObject, int, int> m_FuncOnClickCallBack; public void Init(Action<GameObject, GameObject, int, int> callBack) { Init(callBack, null); } public void Init(Action<GameObject, GameObject, int, int> callBack, Action<GameObject, GameObject, int, int> onClickCallBack, Action<int, bool, GameObject> onButtonClickCallBack) { m_FuncOnButtonClickCallBack = onButtonClickCallBack; Init(callBack, onClickCallBack); } public void Init(Action<GameObject, GameObject, int, int> callBack, Action<GameObject, GameObject, int, int> onClickCallBack) { base.Init(null, null); m_FuncCallBackFunc = callBack; /* Button 处理 */ if (m_ExpandButton == null) { if (m_Content.transform.Find("Button") != null) { m_ExpandButton = m_Content.transform.Find("Button").gameObject; } } if (m_ExpandButton != null) { RectTransform rectTrans = m_ExpandButton.transform.GetComponent<RectTransform>(); m_ExpandButtonX = rectTrans.anchoredPosition.x; m_ExpandButtonY = rectTrans.anchoredPosition.y; SetPoolsButtonObj(m_ExpandButton); m_ExpandButtonWidth = rectTrans.rect.width; m_ExpandButtonHeight = rectTrans.rect.height; var background = m_ExpandButton.transform.Find("background"); if (background != null) { m_BackgroundOriginSize = background.GetComponent<RectTransform>().sizeDelta; } } } public override void ShowList(string numStr) { ClearCell(); //清除所有Cell (非首次调Showlist时执行) int totalCount = 0; int beforeCellCount = 0; string[] numArray = numStr.Split('|'); int buttonCount = numArray.Length; bool isReset; if (m_IsInited && m_ExpandInfos.Length == buttonCount) { isReset = false; } else { m_ExpandInfos = new ExpandInfo[buttonCount]; isReset = true; } for (int k = 0; k < buttonCount; k++) { //-> Button 物体处理 GameObject button = GetPoolsButtonObj(); button.name = k.ToString(); Button buttonComponent = button.GetComponent<Button>(); if (!m_IsAddedListener.ContainsKey(button) && buttonComponent != null) { m_IsAddedListener[button] = true; buttonComponent.onClick.AddListener(delegate () { OnClickExpand(button); }); button.transform.SetSiblingIndex(0); } float pos = 0; //坐标( isVertical ? 记录Y : 记录X ) //-> 计算 Button 坐标 if (m_Direction == e_Direction.Vertical) { pos = m_ExpandButtonHeight * k + m_Spacing * (k + 1); pos += k > 0 ? (m_CellObjectHeight + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row) : 0; button.transform.GetComponent<RectTransform>().anchoredPosition = new Vector3(m_ExpandButtonX, -pos, 0); } else { pos = m_ExpandButtonWidth * k + m_Spacing * (k + 1); pos += k > 0 ? (m_CellObjectWidth + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row) : 0; button.transform.GetComponent<RectTransform>().anchoredPosition = new Vector3(pos, m_ExpandButtonY, 0); } int count = int.Parse(numArray[k]); totalCount += count; //-> 存储数据 ExpandInfo expandInfo = isReset ? new ExpandInfo() : m_ExpandInfos[k]; expandInfo.button = button; expandInfo.cellCount = count; expandInfo.cellInfos = new CellInfo[count]; expandInfo.isExpand = isReset ? m_IsExpand : expandInfo.isExpand; expandInfo.size = m_Direction == e_Direction.Vertical ? (m_CellObjectHeight + m_Spacing) * Mathf.CeilToInt((float)count / m_Row) : (m_CellObjectWidth + m_Spacing) * Mathf.CeilToInt((float)count / m_Row); //计算 需展开的尺寸 //-> 遍历每个按钮下的 Cell for (int i = 0; i < count; i++) { if (!expandInfo.isExpand) break; CellInfo cellInfo = new CellInfo(); float rowPos = 0; //计算每排里面的cell 坐标 //-> 计算Cell坐标 if (m_Direction == e_Direction.Vertical) { pos = m_CellObjectHeight * Mathf.CeilToInt(i / m_Row) + m_Spacing * (Mathf.CeilToInt(i / m_Row) + 1); pos += (m_ExpandButtonHeight + m_Spacing) * (k + 1); pos += (m_CellObjectHeight + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row); rowPos = m_CellObjectWidth * (i % m_Row) + m_Spacing * (i % m_Row); cellInfo.pos = new Vector3(rowPos, -pos, 0); } else { pos = m_CellObjectWidth * Mathf.CeilToInt(i / m_Row) + m_Spacing * (Mathf.CeilToInt(i / m_Row) + 1); pos += (m_ExpandButtonWidth + m_Spacing) * (k + 1); pos += (m_CellObjectHeight + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row); rowPos = m_CellObjectHeight * (i % m_Row) + m_Spacing * (i % m_Row); cellInfo.pos = new Vector3(pos, -rowPos, 0); } //-> 计算是否超出范围 float cellPos = m_Direction == e_Direction.Vertical ? cellInfo.pos.y : cellInfo.pos.x; if (IsOutRange(cellPos)) { cellInfo.obj = null; expandInfo.cellInfos[i] = cellInfo; continue; } //-> 取或创建 Cell GameObject cell = GetPoolsObj(); cell.transform.GetComponent<RectTransform>().anchoredPosition = cellInfo.pos; cell.gameObject.name = k + "-" + i.ToString(); Button cellButtonComponent = cell.GetComponent<Button>(); if (!m_IsAddedListener.ContainsKey(cell) && cellButtonComponent != null) { m_IsAddedListener[cell] = true; cellButtonComponent.onClick.AddListener(delegate () { OnClickCell(cell); }); } //-> 存数据 cellInfo.obj = cell; expandInfo.cellInfos[i] = cellInfo; //-> 回调 函数 Func(m_FuncCallBackFunc, button, cell, expandInfo.isExpand); } beforeCellCount += expandInfo.isExpand ? count : 0; m_ExpandInfos[k] = expandInfo; Func(m_FuncCallBackFunc, button, null, expandInfo.isExpand); } if (!m_IsInited) { //-> 计算 Content 尺寸 if (m_Direction == e_Direction.Vertical) { float contentSize = m_IsExpand ? (m_Spacing + m_CellObjectHeight) * Mathf.CeilToInt((float)totalCount / m_Row) : 0; contentSize += (m_Spacing + m_ExpandButtonHeight) * buttonCount; m_ContentRectTrans.sizeDelta = new Vector2(m_ContentRectTrans.sizeDelta.x, contentSize); } else { float contentSize = m_IsExpand ? (m_Spacing + m_CellObjectWidth) * Mathf.CeilToInt((float)totalCount / m_Row) : 0; contentSize += (m_Spacing + m_ExpandButtonWidth) * buttonCount; m_ContentRectTrans.sizeDelta = new Vector2(contentSize, m_ContentRectTrans.sizeDelta.y); } } m_IsInited = true; } //清除所有Cell (扔到对象池) private void ClearCell() { if (!m_IsInited) return; for (int i = 0, length = m_ExpandInfos.Length; i < length; i++) { if (m_ExpandInfos[i].button != null) { SetPoolsButtonObj(m_ExpandInfos[i].button); m_ExpandInfos[i].button = null; } for (int j = 0, count = m_ExpandInfos[i].cellInfos.Length; j < count; j++) if (m_ExpandInfos[i].cellInfos[j].obj != null) { SetPoolsObj(m_ExpandInfos[i].cellInfos[j].obj); m_ExpandInfos[i].cellInfos[j].obj = null; } } } //Cell 点击事件 public override void OnClickCell(GameObject cell) { int index = int.Parse(((cell.name).Split('-'))[0]); Func(m_FuncOnClickCallBack, m_ExpandInfos[index].button, cell, m_ExpandInfos[index].isExpand); } //收展按钮 点击事件 private void OnClickExpand(GameObject button) { int index = int.Parse(button.name) + 1; OnClickExpand(index); if (m_FuncOnButtonClickCallBack != null) { m_FuncOnButtonClickCallBack(index, m_ExpandInfos[index - 1].isExpand, button); } } public override void OnClickExpand(int index) { index = index - 1; m_ExpandInfos[index].isExpand = !m_ExpandInfos[index].isExpand; //-> 计算 Contant Size Vector2 size = m_ContentRectTrans.sizeDelta; if (m_Direction == e_Direction.Vertical) { float height = m_ExpandInfos[index].isExpand ? size.y + m_ExpandInfos[index].size : size.y - m_ExpandInfos[index].size; m_ContentRectTrans.sizeDelta = new Vector2(size.x, height); } else { float width = m_ExpandInfos[index].isExpand ? size.x + m_ExpandInfos[index].size : size.x - m_ExpandInfos[index].size; m_ContentRectTrans.sizeDelta = new Vector2(width, size.y); } int beforeCellCount = 0; float pos = 0; float rowPos = 0; //-> 重新计算坐标 并 显示处理 for (int k = 0, length = m_ExpandInfos.Length; k < length; k++) { int count = m_ExpandInfos[k].cellCount; if (k >= index) { //-> 计算 按钮位置 GameObject button = m_ExpandInfos[k].button; if (m_Direction == e_Direction.Vertical) { pos = m_ExpandButtonHeight * k + m_Spacing * (k + 1); pos += (m_CellObjectHeight + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row); button.transform.GetComponent<RectTransform>().anchoredPosition = new Vector3(m_ExpandButtonX, -pos, 0); } else { pos = m_ExpandButtonWidth * k + m_Spacing * (k + 1); pos += (m_CellObjectWidth + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row); button.transform.GetComponent<RectTransform>().anchoredPosition = new Vector3(pos, m_ExpandButtonY, 0); } ExpandInfo expandInfo = m_ExpandInfos[k]; for (int i = 0; i < count; i++) { //-> 按钮 收 状态时 if (!expandInfo.isExpand) { if (expandInfo.cellInfos[i].obj != null) { SetPoolsObj(expandInfo.cellInfos[i].obj); m_ExpandInfos[k].cellInfos[i].obj = null; } continue; } CellInfo cellInfo = expandInfo.cellInfos[i]; // * -> 计算每个Cell坐标 if (m_Direction == e_Direction.Vertical) { pos = m_CellObjectHeight * Mathf.FloorToInt(i / m_Row) + m_Spacing * (Mathf.FloorToInt(i / m_Row) + 1); pos += (m_ExpandButtonHeight + m_Spacing) * (k + 1); pos += (m_CellObjectHeight + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row); rowPos = m_CellObjectWidth * (i % m_Row) + m_Spacing * (i % m_Row); cellInfo.pos = new Vector3(rowPos, -pos, 0); } else { pos = m_CellObjectWidth * Mathf.FloorToInt(i / m_Row) + m_Spacing * (Mathf.FloorToInt(i / m_Row) + 1); pos += (m_ExpandButtonWidth + m_Spacing) * (k + 1); pos += (m_CellObjectWidth + m_Spacing) * Mathf.CeilToInt((float)beforeCellCount / m_Row); rowPos = m_CellObjectHeight * (i % m_Row) + m_Spacing * (i % m_Row); cellInfo.pos = new Vector3(pos, -rowPos, 0); } //-> 计算是否超出范围 float cellPos = m_Direction == e_Direction.Vertical ? cellInfo.pos.y : cellInfo.pos.x; if (IsOutRange(cellPos)) { SetPoolsObj(cellInfo.obj); cellInfo.obj = null; m_ExpandInfos[k].cellInfos[i] = cellInfo; continue; } GameObject cell = cellInfo.obj != null ? cellInfo.obj : GetPoolsObj(); cell.transform.GetComponent<RectTransform>().anchoredPosition = cellInfo.pos; cell.gameObject.name = k + "-" + i.ToString(); //-> 回调 if (cellInfo.obj == null) { Func(m_FuncCallBackFunc, button, cell, expandInfo.isExpand); } //-> 添加按钮事件 Button cellButtonComponent = cell.GetComponent<Button>(); if (!m_IsAddedListener.ContainsKey(cell) && cellButtonComponent != null) { m_IsAddedListener[cell] = true; cellButtonComponent.onClick.AddListener(delegate () { OnClickCell(cell); }); } //-> 存数据 cellInfo.obj = cell; m_ExpandInfos[k].cellInfos[i] = cellInfo; } } if (m_ExpandInfos[k].isExpand) { //beforeCellCount += count; /// <summary> /// 修改 2020.10.25 /// </summary> /// <param name="2"> 2 为列数 </param> beforeCellCount += Mathf.CeilToInt((float)count / 2) * 2; } } //展开时候的背景图 ExpandBackground(m_ExpandInfos[index]); Func(m_FuncCallBackFunc, m_ExpandInfos[index].button, null, m_ExpandInfos[index].isExpand); } //展开时候的背景图 private void ExpandBackground(ExpandInfo expandInfo) { //收展时的 list尺寸变化 if (expandInfo.isExpand == false) { var background = expandInfo.button.transform.Find("background"); if (background != null) { RectTransform backgroundTransform = background.GetComponent<RectTransform>(); backgroundTransform.sizeDelta = m_BackgroundOriginSize; } } else { var background = expandInfo.button.transform.Find("background"); if (background != null) { RectTransform backgroundTransform = background.GetComponent<RectTransform>(); float total_h = expandInfo.size; if (m_Direction == e_Direction.Vertical) { if (total_h > 3) { backgroundTransform.sizeDelta = new Vector2(m_BackgroundOriginSize.x, m_BackgroundOriginSize.y + total_h + m_BackgroundMargin); } else { backgroundTransform.sizeDelta = new Vector2(m_BackgroundOriginSize.x, m_BackgroundOriginSize.y); } } else { backgroundTransform.sizeDelta = new Vector2(m_BackgroundOriginSize.x + total_h + m_BackgroundMargin, m_BackgroundOriginSize.y); } } } } protected override void ScrollRectListener(Vector2 value) { Vector3 contentP = m_ContentRectTrans.anchoredPosition; if (m_ExpandInfos == null) return; for (int k = 0, length = m_ExpandInfos.Length; k < length; k++) { ExpandInfo expandInfo = m_ExpandInfos[k]; if (!expandInfo.isExpand) { continue; } int count = expandInfo.cellCount; for (int i = 0; i < count; i++) { CellInfo cellInfo = expandInfo.cellInfos[i]; float rangePos = m_Direction == e_Direction.Vertical ? cellInfo.pos.y : cellInfo.pos.x; if (IsOutRange(rangePos)) { SetPoolsObj(cellInfo.obj); m_ExpandInfos[k].cellInfos[i].obj = null; } else { if (cellInfo.obj == null) { GameObject cell = GetPoolsObj(); cell.transform.GetComponent<RectTransform>().anchoredPosition = cellInfo.pos; cell.name = k + "-" + i; Button cellButtonComponent = cell.GetComponent<Button>(); if (!m_IsAddedListener.ContainsKey(cell) && cellButtonComponent != null) { m_IsAddedListener[cell] = true; cellButtonComponent.onClick.AddListener(delegate () { OnClickCell(cell); }); } cellInfo.obj = cell; m_ExpandInfos[k].cellInfos[i] = cellInfo; Func(m_FuncCallBackFunc, expandInfo.button, cell, expandInfo.isExpand); } } } } } private Stack<GameObject> buttonPoolsObj = new Stack<GameObject>(); //取出 button private GameObject GetPoolsButtonObj() { GameObject button = null; if (buttonPoolsObj.Count > 0) { button = buttonPoolsObj.Pop(); } if (button == null) { button = Instantiate(m_ExpandButton) as GameObject; } button.transform.SetParent(m_Content.transform); button.transform.localScale = Vector3.one; UIUtils.SetActive(button, true); return button; } //存入 button private void SetPoolsButtonObj(GameObject button) { if (button != null) { buttonPoolsObj.Push(button); UIUtils.SetActive(button, false); } } private void Func(Action<GameObject, GameObject, int, int> Func, GameObject button, GameObject selectObject, bool isShow) { string[] objName = { "1", "-2" }; if (selectObject != null) { objName = (selectObject.name).Split('-'); } int buttonNum = int.Parse(button.name) + 1; int num = int.Parse(objName[1]) + 1; if (Func != null) { if (selectObject != null) { //Func(button, selectObject, buttonNum, num, isShow); Func(button, selectObject, buttonNum, num); } else { //Func(button, selectObject, buttonNum, -1, isShow); Func(button, selectObject, buttonNum, -1); } } } } }
-----------------------------------------------------------
//*****************************-》 展开Tips 循环列表 《-**************************** //author: Kim //初始化: // Init(CallBack, OnClickCallBack) //刷新列表: // ShowList(int = 数量) //回调: // 1: Func(cell, index) //列表刷新回调 // 2: OnClickCell(cell, index) 点击Cell 回调 using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace CircularScrollView { public class ExpandTipsCircularScrollView : UICircularScrollView { public GameObject m_ExpandTips; public GameObject m_Arrow; public float m_TipsSpacing; private float m_ExpandTipsHeight; private bool m_IsExpand = false; public override void Init(Action<GameObject, int> callBack, Action<GameObject, int> onClickCallBack) { base.Init(callBack, onClickCallBack); //m_ExpandTips.SetActive(false); UIUtils.SetActive(m_ExpandTips, false); var rectTrans = m_ExpandTips.GetComponent<RectTransform>(); rectTrans.pivot = new Vector2(0, 1); rectTrans.anchorMin = new Vector2(0, 1); rectTrans.anchorMax = new Vector2(0, 1); rectTrans.anchoredPosition = new Vector2(0, 0); rectTrans.sizeDelta = new Vector2(m_ContentWidth, rectTrans.sizeDelta.y); m_ExpandTipsHeight = m_ExpandTips.GetComponent<RectTransform>().rect.height; if( m_Arrow != null) { var arrowRectTrams = m_Arrow.GetComponent<RectTransform>(); arrowRectTrams.pivot = new Vector2(0.5f, 0.5f); arrowRectTrams.anchorMin = new Vector2(0, 0.5f); arrowRectTrams.anchorMax = new Vector2(0, 0.5f); } } public override void ShowList(int num) { base.ShowList(num); m_IsExpand = false; m_IsClearList = true; lastClickCellName = null; UIUtils.SetActive(m_ExpandTips, false); //m_ExpandTips.SetActive(false); } private string lastClickCellName = null; public override void OnClickCell(GameObject cell) { if(lastClickCellName == null || cell.name == lastClickCellName || !m_IsExpand) { m_IsExpand = !m_IsExpand; } lastClickCellName = cell.name; float index = float.Parse(cell.name); int curRow = Mathf.FloorToInt(index / m_Row) + 1; //-> Tips框 显示 //m_ExpandTips.SetActive(m_IsExpand); UIUtils.SetActive(m_ExpandTips, m_IsExpand); m_ExpandTips.transform.localPosition = new Vector3(0, -((m_Spacing + m_CellObjectHeight) * curRow + m_TipsSpacing), 0); //-> Content尺寸 计算 float contentHeight = m_IsExpand ? m_ContentHeight + m_ExpandTipsHeight + m_TipsSpacing : m_ContentHeight; contentHeight = contentHeight < m_PlaneHeight ? m_PlaneHeight : contentHeight; m_ContentRectTrans.sizeDelta = new Vector2(m_ContentWidth, contentHeight); m_MinIndex = -1; for(int i = 0, length = m_CellInfos.Length ; i < length; i++) { CellInfo cellInfo = m_CellInfos[i]; float pos = 0; // Y 坐标 float rowPos = 0; //计算每排里面的cell 坐标 pos = m_CellObjectHeight * Mathf.FloorToInt(i / m_Row) + m_Spacing * (Mathf.FloorToInt(i / m_Row) + 1); rowPos = m_CellObjectWidth * (i % m_Row) + m_Spacing * (i % m_Row); pos += (i/m_Row >= curRow && m_IsExpand) ? m_ExpandTipsHeight + m_TipsSpacing*2 - m_Spacing : 0; //往下移 Tips框高 和 距离 cellInfo.pos = new Vector3(rowPos, -pos, 0); if(IsOutRange(-pos)) { if(cellInfo.obj != null) { SetPoolsObj(cellInfo.obj); cellInfo.obj = null; } } else { //-> 记录显示范围中的 首位index 和 末尾index m_MinIndex = m_MinIndex == -1 ? i : m_MinIndex;// 首位 Index m_MaxIndex = i; // 末尾 Index GameObject cellObj = cellInfo.obj == null ? GetPoolsObj() : cellInfo.obj; cellObj.GetComponent<RectTransform>().anchoredPosition = cellInfo.pos; cellInfo.obj = cellObj; } m_CellInfos[i] = cellInfo; } if (m_Arrow != null) { var arrowObj = m_Arrow.transform.GetComponent<RectTransform>(); arrowObj.anchoredPosition = new Vector2(cell.transform.localPosition.x + (m_CellObjectWidth / 2), arrowObj.anchoredPosition.y); } Func(m_FuncOnClickCallBack, cell); } private Dictionary<GameObject, bool> isAddedListener = new Dictionary<GameObject, bool>(); protected override GameObject GetPoolsObj() { GameObject cell = base.GetPoolsObj(); if (!isAddedListener.ContainsKey(cell)) { Button button = cell.GetComponent<Button>() == null ? cell.AddComponent<Button>() : cell.GetComponent<Button>(); button.onClick.AddListener(delegate () { OnClickCell(cell); }); isAddedListener[cell] = true; } return cell; } } }
------------------------------------------
//*****************************-》 滑动翻页 循环列表 《-**************************** //author: Kim //初始化: // Init(CallBack) // Init(CallBack, SlidePageCallBack) SlidePageCallBack = 返回当前页的回调 //刷新列表: // ShowList(int = 数量) //回调: // 1: Func(cell, index) //列表刷新回调 // 2: SlidePageFunc( int = pageIndex ) 翻页回调 param = 当前页 using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace CircularScrollView { public class FlipPageCircularScrollView : UICircularScrollView { public int m_OnePageCount = 1; //每页显示的项目 public float m_SlideSpeed = 5; //滑动速度 public bool m_IsMaxRange = false; // * -> 是否开启 导航图标模式 public bool m_IsOpenNavIcon = false; //-> 开启 导航图标模式时 使用以下变量 public float m_IconSize = 20; public float m_IconSpacing = 5.0f; public Sprite m_SelectIcon = null; public Sprite m_NormalIcon = null; public Transform m_ObjNavigation; // <- private int m_AllPageCount; //总页数 private int m_NowIndex = 0; //当前位置索引 private int m_LastIndex = -1; //上一次的索引 private bool m_IsDrag = false; //是否拖拽中 private float m_TargetPos = 0; //滑动的目标位置 private List<float> m_ListPageValue = new List<float> { 0 }; //总页数索引比列 0-1 private List<Image> m_NavigationList = new List<Image>(); protected new Action<int> m_FuncOnClickCallBack; public override void ShowList(int num) { base.ShowList(num); ListPageValueInit(); } //翻页到某一页 public override void SetToPageIndex(int index) { m_IsDrag = false; m_NowIndex = index - 1; m_TargetPos = m_ListPageValue[m_NowIndex]; for (int i = 0; i < m_NavigationList.Count; i++) { if (i == m_NowIndex) { m_NavigationList[m_NowIndex].sprite = m_SelectIcon; } else { m_NavigationList[i].sprite = m_NormalIcon; } } if (m_FuncOnClickCallBack != null) { Func(m_FuncOnClickCallBack, m_NowIndex); } } //每页比例 void ListPageValueInit() { m_NavigationList.Clear(); m_AllPageCount = m_MaxCount - m_OnePageCount; if (m_MaxCount != 0) { for (float i = 1; i <= m_AllPageCount; i++) { m_ListPageValue.Add((i / m_AllPageCount)); } } if (m_IsOpenNavIcon && m_MaxCount > 1) { if (m_ObjNavigation == null) { m_ObjNavigation = transform.Find("m_ObjNavigation"); } float[] posArray = new float[m_MaxCount]; if (m_MaxCount == 1) { posArray[0] = 0; } else { float startX = -m_MaxCount / 2 * m_IconSpacing; for (int i = 0; i < m_MaxCount; i++) { posArray[i] = startX + m_IconSpacing * i; } } for (int i = 0; i < m_MaxCount; i++) { GameObject icon = null; if (m_ObjNavigation.Find(string.Format("icon{0}", i)) != null) { icon = m_ObjNavigation.Find(string.Format("icon{0}", i)).gameObject; } else { icon = new GameObject(string.Format("icon{0}", i)); } icon.transform.parent = m_ObjNavigation; Image img = null; if (icon.GetComponent<Image>() == null) { img = icon.AddComponent<Image>(); } else { img = icon.GetComponent<Image>(); } if (i == 0) { img.sprite = m_SelectIcon; } else { img.sprite = m_NormalIcon; } img.rectTransform.sizeDelta = new Vector2(m_IconSize, m_IconSize); icon.transform.localScale = Vector3.one; icon.transform.localPosition = new Vector3(posArray[i], 0, 0); m_NavigationList.Add(img); } } if (m_FuncOnClickCallBack != null) { Func(m_FuncOnClickCallBack, m_NowIndex); } } void Update() { if (!m_IsDrag) { if (m_ScrollRect == null) return; if(m_Direction == e_Direction.Vertical) { m_ScrollRect.verticalNormalizedPosition = Mathf.Lerp(m_ScrollRect.verticalNormalizedPosition, m_TargetPos, Time.deltaTime * m_SlideSpeed); } else { m_ScrollRect.horizontalNormalizedPosition = Mathf.Lerp(m_ScrollRect.horizontalNormalizedPosition, m_TargetPos, Time.deltaTime * m_SlideSpeed); } } } /// 拖动开始 public override void OnBeginDrag(PointerEventData eventData) { base.OnBeginDrag(eventData); m_IsDrag = true; } /// 拖拽结束 public override void OnEndDrag(PointerEventData eventData) { base.OnEndDrag(eventData); m_IsDrag = false; if (m_ListPageValue.Count == 1) { return; } float tempPos = 0; if(m_Direction == e_Direction.Vertical) { tempPos = m_ScrollRect.verticalNormalizedPosition; } else { tempPos = m_ScrollRect.horizontalNormalizedPosition; } if (m_IsMaxRange) { //获取拖动的值 var index = 0; float offset = Mathf.Abs(m_ListPageValue[index] - tempPos); //拖动的绝对值 for (int i = 1; i < m_ListPageValue.Count; i++) { float temp = Mathf.Abs(tempPos - m_ListPageValue[i]); if (temp < offset) { index = i; offset = temp; } } m_TargetPos = m_ListPageValue[index]; m_NowIndex = index; if (m_NowIndex != m_LastIndex && m_FuncOnClickCallBack != null) { Func(m_FuncOnClickCallBack, m_NowIndex); } m_LastIndex = m_NowIndex; } else { float currPos = m_ListPageValue[m_NowIndex]; if (tempPos > currPos) { m_NowIndex++; } else if (tempPos < currPos) { m_NowIndex--; } if (m_NowIndex < 0) { m_NowIndex = 0; } if (m_NowIndex > m_ListPageValue.Count - 1) { m_NowIndex = m_ListPageValue.Count - 1; } m_TargetPos = m_ListPageValue[m_NowIndex]; if (m_NowIndex != m_LastIndex && m_FuncOnClickCallBack != null) { Func(m_FuncOnClickCallBack, m_NowIndex); } m_LastIndex = m_NowIndex; } if (m_IsOpenNavIcon) { int length = m_NavigationList.Count; for (int i = 0; i < length; i++) { Image img = m_NavigationList[i]; if (i == m_NowIndex) { img.sprite = m_SelectIcon; } else { img.sprite = m_NormalIcon; } } } } //翻页时的回调 private void Func(Action<int> Func, int index) { if (Func == null) return; Func(index + 1); } } }
引用原文:忘记了 = = !
推荐参考:https://blog.csdn.net/flj135792468/article/details/120265718
https://blog.csdn.net/weixin_43109909/article/details/120254614