//**********************************************// //作者:#何健# //日期:#2016.10.09# //简述:#ScrollView优化,使用一定数量子项实现大量数据循环加载# //*********************************************// using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Text; namespace Thousandto.Plugins.Common { /// /// 类BackPackItem说明 /// [RequireComponent(typeof(UIGrid))] public class UILoopScrollViewBase : MonoCacheBase { #region Members /// /// 存储物件列表 /// private List m_itemList = new List(); /// /// 起始下标 /// private int _startIndex = 1; /// /// 最大长度 /// private int _maxCount; /// /// 父ScrollView /// public UIScrollView _scrollView; /// /// grid /// public UIGrid _grid; /// /// templateItem /// public GameObject _templateItem; /// /// 物件刷新代理事件 /// /// public delegate void OnItemChange(Transform obj, string name, bool isClear); private OnItemChange m_pItemChangeCallBack; private Vector2 _scrollViewPos = new Vector2(0, 0); private Vector3 lastPos; private bool _isRecodePos = false; #endregion #region 回调处理 /// /// 设置代理 /// /// public void SetDelegate(OnItemChange _onItemChange) { m_pItemChangeCallBack = _onItemChange; } /// /// 物件刷新代理事件 /// /// private void OnItemChangeMsg(Transform obj,string name, bool isClear) { if (m_pItemChangeCallBack != null) { m_pItemChangeCallBack(obj, name, isClear); } } #endregion /// /// 初始化表 /// public void Init(int maxCount, GameObject templateItem = null, int waitCount = 1, bool isResetScrool = true) { _isRecodePos = false; _maxCount = maxCount; if (isResetScrool) { // 如果传入有控件则以传入的为模板如果没有则查找grid下面第一个子控件 _grid = transform.GetComponent(); _scrollView = transform.parent.GetComponent(); _grid.gameObject.SetActive(true); var _num = _maxCount % _grid.maxPerLine; if (_num != 0) { _maxCount = _maxCount + _grid.maxPerLine - _num; } if (templateItem) { _templateItem = templateItem; } else { _templateItem = _grid.transform.GetChild(0).gameObject; } try { StartCoroutine(Respositon(waitCount)); } finally { } } else { //当前显示出来的第一个格子,在grid数据中的index var childCount = _grid.transform.childCount; int index = Mathf.FloorToInt((_maxCount - childCount) / _grid.maxPerLine); for (int i = index * _grid.maxPerLine; i < childCount + index * _grid.maxPerLine; i++) { if (i >= _maxCount) return; FillItem(i - index * _grid.maxPerLine + _startIndex, i + _startIndex, i == childCount + index * _grid.maxPerLine - 1); } } } private IEnumerator Respositon(int waitCount = 0) { InitGird(); _grid.Reposition(); yield return waitCount; _scrollView.ResetPosition(); _isRecodePos = true; } private void InitGird() { m_itemList.Clear(); // 将现有的子项添加到容器 for (int i = 0; i < _grid.transform.childCount; i++) { GameObject go = _grid.transform.GetChild(i).gameObject; //go.SetActive(false); m_itemList.Add(go); } int fillCount = 0; //当前scrollView被填满的格子数 int lastIndex = 0; //上次显示出来的第一个格子,在grid数据中的index var _indexDis = 0f; UIPanel panel = _scrollView.GetComponent(); if (_scrollView.movement == UIScrollView.Movement.Vertical) { fillCount = Mathf.CeilToInt(panel.height / _grid.cellHeight); fillCount = fillCount * _grid.maxPerLine; _indexDis = _grid.cellHeight; } else if (_scrollView.movement == UIScrollView.Movement.Horizontal) { fillCount = Mathf.CeilToInt(panel.width / _grid.cellWidth); _indexDis = _grid.cellWidth; } //if (_maxCount < fillCount + _grid.maxPerLine) // _maxCount = fillCount + _grid.maxPerLine; int childCount = _maxCount; // 如果item数量大于填满显示面板的数量做优化 if (childCount > fillCount + _grid.maxPerLine) { childCount = fillCount + _grid.maxPerLine; // 拖拽刷新面板 panel.onClipMove = (uiPanel) => { Vector3 delata = lastPos - panel.transform.localPosition; float distance = System.Math.Abs(delata.y) > 0.5 ? delata.y : delata.x; // 满的时候向上滑不管它 if ((distance > 0 && _scrollView.movement == UIScrollView.Movement.Vertical) || (distance < 0 && _scrollView.movement == UIScrollView.Movement.Horizontal)) return; if (distance < 0) distance = -distance; //当前显示出来的第一个格子,在grid数据中的index int index = Mathf.FloorToInt(distance / _indexDis); // 拖拽不满一个单元格 if (index == lastIndex) return; // 拉到底了 if (index + childCount > _maxCount) { for (int i = 1; i <= _grid.transform.childCount; i++) { if (i >= _maxCount) return; var _newKey = _maxCount >= _grid.transform.childCount ? _maxCount - _grid.transform.childCount + i : i; FillItem(i, _newKey, i == _grid.transform.childCount); } return; } lastIndex = index; // 重刷 if ((index - 1) * _grid.maxPerLine + childCount < _maxCount) { for (int i = index * _grid.maxPerLine; i < childCount + index * _grid.maxPerLine; i++) { if (i >= _maxCount) return; FillItem(i - index * _grid.maxPerLine + _startIndex, i + _startIndex, i == childCount + index * _grid.maxPerLine - 1); } } }; } _scrollView.onStoppedMoving = OnDragFinished; // 添加能填满UI数量的子项 var allCount = fillCount + _grid.maxPerLine; for (int i = 0; i < allCount; i++) { bool isClear = false; if (i == 0) { isClear = true; } if (i >= _maxCount) { break; } GameObject go = null; if (i < m_itemList.Count) { go = m_itemList[i]; } else { go = NGUITools.AddChild(_grid.gameObject, _templateItem); m_itemList.Add(go); } go.SetActive(true); FillItem(i + _startIndex, i + _startIndex, isClear); //if (m_itemList.Count > i) //{ // FillItem(i + _startIndex, i + _startIndex, isClear); // continue; //} //GameObject go = NGUITools.AddChild(_grid.gameObject, _templateItem); //go.SetActive(true); //m_itemList.Add(go); //FillItem(i + _startIndex, i + _startIndex, isClear); } for (int i = allCount; i < m_itemList.Count; i++) { m_itemList[i].SetActive(false); } lastPos = panel.transform.localPosition; } public void OnDragFinished() { if (_scrollView.movement == UIScrollView.Movement.Vertical) { int indexY = (int)_scrollViewPos.y; if (indexY + 10 > (int)_scrollView.transform.localPosition.y && indexY - 10 < (int)_scrollView.transform.localPosition.y) { for (int i = 0; i < _grid.transform.childCount; i++) { if (i >= _maxCount) return; FillItem(i + _startIndex, i + _startIndex, i == _grid.transform.childCount - 1); } } } else if(_scrollView.movement == UIScrollView.Movement.Horizontal) { int indexY = (int)_scrollViewPos.x; if (indexY + 10 > (int)_scrollView.transform.localPosition.x && indexY - 10 < (int)_scrollView.transform.localPosition.x) { for (int i = 0; i < _grid.transform.childCount; i++) { if (i >= _maxCount) return; FillItem(i + _startIndex, i + _startIndex, i == _grid.transform.childCount - 1); } } } } // 修改子项位置 public void FillItem(int oldIndex, int index, bool isClear) { //Debug.Log("-----oldIndex=" + oldIndex + ",index = " + index + ", itemListCount=" + m_itemList.Count); int iListIndex = oldIndex - _startIndex; if (m_itemList.Count <= iListIndex) return; string oldKey = m_itemList[iListIndex].name; string newKey = index.ToString(); m_itemList[iListIndex].name = newKey; if (_scrollView.movement == UIScrollView.Movement.Horizontal)// 如果是水平滑动,则只有一排 { m_itemList[iListIndex].transform.localPosition = new Vector3(_grid.cellWidth * (index - 1), 0, 0); } else if (_scrollView.movement == UIScrollView.Movement.Vertical) // 纵向滑动时有可能有多列 { int count = index / _grid.maxPerLine; int countLess = index % _grid.maxPerLine; if(countLess == 0) { countLess = _grid.maxPerLine - _startIndex; if(_startIndex != 0) { count -= 1; } } else { countLess -= _startIndex; } m_itemList[iListIndex].transform.localPosition = new Vector3(countLess * _grid.cellWidth, -_grid.cellHeight * count, 0); m_itemList[iListIndex].gameObject.SetActive(true); } OnItemChangeMsg(m_itemList[iListIndex].transform, newKey, isClear); } // 修改最大格子数 public void OnSetMaxIndex(int max) { _maxCount = max; if(_grid != null) { var _num = _maxCount % _grid.maxPerLine; if (_num != 0) { _maxCount = _maxCount - _grid.maxPerLine + _num; } } } // 修改最大格子数 public int OnGetMaxIndex() { return _maxCount; } //重置lastpos public void ResetPos() { lastPos = _scrollView.GetComponent().transform.localPosition; } private void Update() { if (_isRecodePos) { _scrollViewPos = _scrollView.transform.localPosition; ResetPos(); _isRecodePos = false; } } } }