123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine.UI;
- using DG.Tweening;
- /// <summary>
- /// 滚动列表优化
- /// </summary>
- [DisallowMultipleComponent]
- public class UIWarpContent1 : MonoBehaviour
- {
- /// <summary>
- /// 元素初始化
- /// </summary>
- /// <param name="go"> 游戏对象 </param>
- /// <param name="dataIndex"> 数据索引 </param>
- public delegate void OnInitializeItem(GameObject go, int dataIndex);
- /// <summary>
- /// 元素初始化
- /// </summary>
- public OnInitializeItem onInitializeItem;
- /// <summary>
- /// 排列
- /// </summary>
- public enum Arrangement
- {
- /// <summary>
- /// 横
- /// </summary>
- Horizontal,
- /// <summary>
- /// 竖
- /// </summary>
- Vertical,
- }
- /// <summary>
- /// 排列
- /// </summary>
- public Arrangement arrangement = Arrangement.Horizontal;
- /// <summary>
- /// Maximum children per line.
- /// If the arrangement is horizontal, this denotes the number of columns.
- /// If the arrangement is vertical, this stands for the number of rows.
- /// </summary>
- [Range(1, 50)]
- public int maxPerLine = 1;
- /// <summary>
- /// The width of each of the cells.
- /// </summary>
- public float cellWidth = 200f;
- /// <summary>
- /// The height of each of the cells.
- /// </summary>
- public float cellHeight = 200f;
- /// <summary>
- /// The Width Space of each of the cells.
- /// </summary>
- [Range(0, 50)]
- public float cellWidthSpace = 0f;
- /// <summary>
- /// The Height Space of each of the cells.
- /// </summary>
- [Range(0, 50)]
- public float cellHeightSpace = 0f;
- /// <summary>
- /// 窗口能容纳的 行数 或 列数
- /// </summary>
- [Range(0, 30)]
- public int viewCount = 5;
- /// <summary>
- /// scroll view 对象
- /// </summary>
- public ScrollRect scrollRect = null;
- /// <summary>
- /// content 对象
- /// </summary>
- public RectTransform content = null;
- /// <summary>
- /// 元素预制物体
- /// </summary>
- public GameObject goItemPrefab = null;
- /// <summary>
- /// 数据的数量
- /// </summary>
- private int mDataCount = 0;
- /// <summary>
- /// 当前所处的行数
- /// </summary>
- private int curScrollPerLineIndex = -1;
- /// <summary>
- /// 正在使用中的元素
- /// </summary>
- private List<UIWarpContentItem1> listItem = new List<UIWarpContentItem1>();
- /// <summary>
- /// 未在使用中的元素
- /// </summary>
- private Queue<UIWarpContentItem1> unUseItem = new Queue<UIWarpContentItem1>();
- /// <summary>
- /// 初始化
- /// </summary>
- private void Awake()
- {
- }
- /// <summary>
- /// 初始化
- /// </summary>
- /// <param name="dataCount"> 数据的数量 </param>
- public void Init(int dataCount)
- {
- if (scrollRect == null || content == null || goItemPrefab == null)
- {
- Debug.LogError("异常:请检测<" + gameObject.name + ">对象上UIWarpContent对应ScrollRect、Content、GoItemPrefab 是否存在值...." + scrollRect + " _" + content + "_" + goItemPrefab);
- return;
- }
- // 不显示元素预制物体
- goItemPrefab.SetActive(false);
-
- scrollRect.onValueChanged.RemoveAllListeners();
- scrollRect.onValueChanged.AddListener(onValueChanged);
- // 如果数据数量为 0 ,没有初始化的必要
- if (dataCount <= 0)
- {
- return;
- }
- // 设置数据的数量,并计算 content 的尺寸
- setDataCount(dataCount);
- unUseItem.Clear();
- listItem.Clear();
- setUpdateRectItem(0);
- }
- /// <summary>
- /// 标志位
- /// </summary>
- public bool hasPlayEffect = false;
- /// <summary>
- /// 特效种类,0就是从下往上,1是从左往右,2是从右往左.
- /// </summary>
- public int KindOfEffect = 0;
- /// <summary>
- /// 递加种子
- /// </summary>
- public int seedNum = 0;
- /// <summary>
- /// 用了dotween后,在快速连续刷新的时候,会有显示不到位的情况,需要这样重置一下才行
- /// 但是用了以后会卡顿,正在调整
- /// </summary>
- /// <param name="dataCount"></param>
- public void DataZero()
- {
- if (scrollRect == null || content == null || goItemPrefab == null)
- {
- Debug.LogError("异常:请检测<" + gameObject.name + ">对象上UIWarpContent对应ScrollRect、Content、GoItemPrefab 是否存在值...." + scrollRect + " _" + content + "_" + goItemPrefab);
- return;
- }
- // 因为数据改变了,元素要重新获取数据
- for (int i = listItem.Count - 1; i >= 0; i--)
- {
- UIWarpContentItem1 item = listItem[i];
- DelItem(item.Index);
- }
- seedNum = 0;
- hasPlayEffect = false;
- //// 计算当前所处的行数,刷新
- //int _curScrollPerLineIndex = getCurScrollPerLineIndex();
- //setUpdateRectItem(_curScrollPerLineIndex);
- }
- /// <summary>
- /// 数据改变了,比如切换分类功能,全部,前排,中排,后排,元素要重新获取数据
- /// </summary>
- /// <param name="dataCount"> 数据的数量 </param>
- /// <param name="bResetPos"> 是否返回初始位置 </param>
- public void DataChange(int dataCount, bool bResetPos)
- {
-
- if (scrollRect == null || content == null || goItemPrefab == null)
- {
- Debug.LogError("异常:请检测<" + gameObject.name + ">对象上UIWarpContent对应ScrollRect、Content、GoItemPrefab 是否存在值...." + scrollRect + " _" + content + "_" + goItemPrefab);
- return;
- }
- // 重新设置数量,重新计算 content 的尺寸
- setDataCount(dataCount);
- // 因为数据改变了,元素要重新获取数据
- for (int i = listItem.Count - 1; i >= 0; i--)
- {
- UIWarpContentItem1 item = listItem[i];
-
- item.Index = -1;
- listItem.Remove(item);
- unUseItem.Enqueue(item);
- }
- seedNum = 0;
- hasPlayEffect = false;
-
- if (bResetPos)
- {
-
- hasPlayEffect = true;
- content.anchoredPosition = Vector3.zero;
- }
- // 计算当前所处的行数,刷新
- int _curScrollPerLineIndex = getCurScrollPerLineIndex();
- setUpdateRectItem(_curScrollPerLineIndex);
- //============== 2017/1/22 临时 ====================
- //if (hasPlayEffect == false)
- //{
- // hasPlayEffect = true;
- //}
- //========================================
- }
- /// <summary>
- /// 设置数据的数量,并重新计算 content 的尺寸
- /// </summary>
- /// <param name="count"> 数据的数量 </param>
- private void setDataCount(int count)
- {
- if (mDataCount == count)
- {
- return;
- }
- mDataCount = count;
- // 计算 content 的尺寸
- setUpdateContentSize();
- }
- /// <summary>
- /// scroll view 拖动时触发
- /// </summary>
- /// <param name="vt2"> 拖动数值 </param>
- private void onValueChanged(Vector2 vt2)
- {
- int _curScrollPerLineIndex = getCurScrollPerLineIndex();
- if (_curScrollPerLineIndex == curScrollPerLineIndex)
- {
- return;
- }
- hasPlayEffect = false;
- setUpdateRectItem(_curScrollPerLineIndex);
- }
- /// <summary>
- /// 刷新元素
- /// </summary>
- /// <param name="scrollPerLineIndex"> 当前所处的行数 </param>
- private void setUpdateRectItem(int scrollPerLineIndex)
- {
- if (scrollPerLineIndex < 0)
- {
- return;
- }
- curScrollPerLineIndex = scrollPerLineIndex;
- int startDataIndex = curScrollPerLineIndex * maxPerLine;
- int endDataIndex = (curScrollPerLineIndex + viewCount) * maxPerLine;
- // 移除
- for (int i = listItem.Count - 1; i >= 0; i--)
- {
- UIWarpContentItem1 item = listItem[i];
- int index = item.Index;
- if (index < startDataIndex || index >= endDataIndex)
- {
- item.Index = -1;
- listItem.Remove(item);
- unUseItem.Enqueue(item);
- }
- }
- // 显示
- for (int dataIndex = startDataIndex; dataIndex < endDataIndex; dataIndex++)
- {
- if (dataIndex >= mDataCount)
- {
- continue;
- }
- if (isExistDataByDataIndex(dataIndex))
- {
- continue;
- }
- createItem(dataIndex);
- }
- }
- /// <summary>
- /// 添加当前数据索引数据
- /// </summary>
- /// <param name="dataIndex"> 数据索引 </param>
- public void AddItem(int dataIndex)
- {
- if (dataIndex < 0 || dataIndex > mDataCount)
- {
- return;
- }
- // 检测是否需添加gameObject
- bool isNeedAdd = false;
- for (int i = listItem.Count - 1; i >= 0; i--)
- {
- UIWarpContentItem1 item = listItem[i];
- if (item.Index >= (mDataCount - 1))
- {
- isNeedAdd = true;
- break;
- }
- }
- setDataCount(mDataCount + 1);
- if (isNeedAdd)
- {
- for (int i = 0; i < listItem.Count; i++)
- {
- UIWarpContentItem1 item = listItem[i];
- int oldIndex = item.Index;
- if (oldIndex >= dataIndex)
- {
- item.Index = oldIndex + 1;
- }
- item = null;
- }
- setUpdateRectItem(getCurScrollPerLineIndex());
- }
- else
- {
- // 重新刷新数据
- for (int i = 0; i < listItem.Count; i++)
- {
- UIWarpContentItem1 item = listItem[i];
- int oldIndex = item.Index;
- if (oldIndex >= dataIndex)
- {
- item.Index = oldIndex;
- }
- item = null;
- }
- }
- }
- /// <summary>
- /// 删除当前数据索引下数据
- /// </summary>
- /// <param name="dataIndex"> 数据索引 </param>
- public void DelItem(int dataIndex)
- {
- if (dataIndex < 0 || dataIndex >= mDataCount)
- {
- return;
- }
- ////删除item逻辑三种情况
- ////1.只更新数据,不销毁gameObject,也不移除gameobject
- ////2.更新数据,且移除gameObject,不销毁gameObject
- ////3.更新数据,销毁gameObject
- bool isNeedDestroyGameObject = (listItem.Count >= mDataCount);
- setDataCount(mDataCount - 1);
- for (int i = listItem.Count - 1; i >= 0; i--)
- {
- UIWarpContentItem1 item = listItem[i];
- int oldIndex = item.Index;
- if (oldIndex == dataIndex)
- {
- listItem.Remove(item);
- if (isNeedDestroyGameObject)
- {
- GameObject.Destroy(item.gameObject);
- }
- else
- {
- item.Index = -1;
- unUseItem.Enqueue(item);
- }
- }
- if (oldIndex > dataIndex)
- {
- item.Index = oldIndex - 1;
- }
- }
- setUpdateRectItem(getCurScrollPerLineIndex());
- }
- /// <summary>
- /// 根据数据索引计算在 content 下的 local position
- /// </summary>
- /// <param name="index"> 数据索引 </param>
- /// <returns> 位置 </returns>
- public Vector3 getLocalPositionByIndex(int index)
- {
- if (index < 0)
- {
- return new Vector3(-2000.0f, 2000.0f, 0.0f);
- }
- float x = 0f;
- float y = 0f;
- float z = 0f;
- switch (arrangement)
- {
- // 水平方向
- case Arrangement.Horizontal:
- {
- x = (index / maxPerLine) * (cellWidth + cellWidthSpace);
- y = -(index % maxPerLine) * (cellHeight + cellHeightSpace);
- }
- break;
- // 垂着方向
- case Arrangement.Vertical:
- {
- x = (index % maxPerLine) * (cellWidth + cellWidthSpace);
- y = -(index / maxPerLine) * (cellHeight + cellHeightSpace);
- }
- break;
- default:
- {
- // 不需要处理
- }
- break;
- }
- return new Vector3(x, y, z);
- }
- /// <summary>
- /// 创建元素
- /// </summary>
- /// <param name="dataIndex"> 数据索引 </param>
- private void createItem(int dataIndex)
- {
- UIWarpContentItem1 item = null;
- if (unUseItem.Count > 0)
- {
- item = unUseItem.Dequeue();
- }
- else
- {
- GameObject temp = addChild(goItemPrefab, content);
- item = temp.GetComponent<UIWarpContentItem1>();
- if (item == null)
- {
- AssemblyHelper.Instance.BindScript("UIWarpContentItem1", temp);
- item = temp.GetComponent<UIWarpContentItem1>();
- }
- }
- Vector3 xxV = getLocalPositionByIndex(dataIndex);
- item.transform.localPosition = new Vector3(xxV.x, xxV.y - 2000, xxV.z);
- item.WarpContent = this;
- item.Index = dataIndex;
- listItem.Add(item);
- }
- /// <summary>
- /// 当前数据是否存在 List 中
- /// </summary>
- /// <param name="dataIndex"> 数据索引 </param>
- /// <returns> 是否已存在 </returns>
- private bool isExistDataByDataIndex(int dataIndex)
- {
- if (listItem == null || listItem.Count <= 0)
- {
- return false;
- }
- for (int i = 0; i < listItem.Count; i++)
- {
- if (listItem[i].Index == dataIndex)
- {
- return true;
- }
- }
- return false;
- }
- /// <summary>
- /// 根据Content偏移,计算当前开始显示所在数据列表中的行或列
- /// </summary>
- /// <returns> 行数 或 列数 </returns>
- private int getCurScrollPerLineIndex()
- {
- int result = 0;
- switch (arrangement)
- {
- // 水平方向
- case Arrangement.Horizontal:
- {
- result = Mathf.FloorToInt(-(content.anchoredPosition.x) / (cellWidth + cellWidthSpace));
- }
- break;
- // 垂着方向
- case Arrangement.Vertical:
- {
- result = Mathf.FloorToInt((content.anchoredPosition.y) / (cellHeight + cellHeightSpace));
- }
- break;
- default:
- {
- // 不需要处理
- }
- break;
- }
- if (result < 0)
- {
- result = 0;
- }
- return result;
- }
- /// <summary>
- /// 计算 content 的尺寸
- /// </summary>
- private void setUpdateContentSize()
- {
- // 行数,向上取整
- int lineCount = Mathf.CeilToInt((float)mDataCount / maxPerLine);
- switch (arrangement)
- {
- case Arrangement.Horizontal:
- {
- content.sizeDelta = new Vector2((cellWidth * lineCount) + (cellWidthSpace * (lineCount - 1)), content.sizeDelta.y);
- }
- break;
- case Arrangement.Vertical:
- {
- content.sizeDelta = new Vector2(content.sizeDelta.x, (cellHeight * lineCount) + (cellHeightSpace * (lineCount - 1)));
- }
- break;
- default:
- {
- // 不需要处理
- }
- break;
- }
- }
- /// <summary>
- /// 实例化预设对象 、添加实例化对象到指定的子对象下
- /// </summary>
- /// <param name="goPrefab"> 元素预制物体 </param>
- /// <param name="parent"> 父节点 </param>
- /// <returns> 新创建的元素对象 </returns>
- private GameObject addChild(GameObject goPrefab, Transform parent)
- {
- if (goPrefab == null || parent == null)
- {
- Debug.LogError("异常。UIWarpContent1.cs addChild(goPrefab = null || parent = null)");
- return null;
- }
- GameObject goChild = GameObject.Instantiate(goPrefab) as GameObject;
- goChild.transform.SetParent(parent, false);
- goChild.SetActive(true);
- return goChild;
- }
- /// <summary>
- /// 销毁
- /// </summary>
- private void OnDestroy()
- {
- scrollRect = null;
- content = null;
- goItemPrefab = null;
- onInitializeItem = null;
- listItem.Clear();
- unUseItem.Clear();
- listItem = null;
- unUseItem = null;
- }
-
- }
|