LoopScrollView

来源:互联网 发布:淘宝做什么生意好赚钱 编辑:程序博客网 时间:2024/06/05 09:38
using UnityEngine;using System.Collections.Generic;/// <summary>/// 这个类主要做了一件事,就是优化了,NGUI UIScrollView 在数据量很多都时候,/// 创建过多都GameObject对象,造成资源浪费./// </summary>public class LoopScrollView : MonoBehaviour{public enum ArrangeDirection{Left_to_Right,Right_to_Left,Up_to_Down,Down_to_Up,}/// <summary>/// items的排列方式/// </summary>public ArrangeDirection arrangeDirection = ArrangeDirection.Up_to_Down;/// <summary>/// 列表脚本/// </summary>public UIScrollView scrollView;public GameObject itemParent;/// <summary>/// 列表单项模板/// </summary>public GameObject itemPrefab;[HideInInspector]public int maxPoolItem = 3;/// <summary>/// The items list./// </summary>public List<LoopItemObject> itemsList;/// <summary>/// The datas list./// </summary>public List<object> datasList;/// <summary>/// itemsList的第一个元素/// </summary>LoopItemObject firstItem;/// <summary>/// itemsList的最后一个元素/// </summary>LoopItemObject lastItem;public delegate void DelegateHandler (LoopItemObject item, object data);/// <summary>/// 响应/// </summary>public DelegateHandler OnItemInit;/// <summary>/// 第一item的起始位置/// </summary>public Vector3 itemStartPos = Vector3.zero;/// <summary>/// 菜单项间隙/// </summary>public float gapDis = 0f;// 对象池// 再次优化,频繁的创建与销毁Queue<LoopItemObject> itemLoop = new Queue<LoopItemObject> ();void Awake (){if (itemPrefab == null || scrollView == null || itemParent == null) {Debug.LogError ("LoopScrollView.Awake() 有属性没有在inspector中赋值");}// 设置scrollview的movementif (arrangeDirection == ArrangeDirection.Up_to_Down || arrangeDirection == ArrangeDirection.Down_to_Up) {scrollView.movement = UIScrollView.Movement.Vertical;} else {scrollView.movement = UIScrollView.Movement.Horizontal;}scrollView.panel.onClipMove = OnMove;}void OnMove(UIPanel panel){Validate();scrollView.Scroll(0.0001f);}void Update(){Validate();}/// <summary>/// 检验items的两端是否要补上或删除/// </summary>void Validate (bool moveToEnd = false){if (datasList == null || datasList.Count == 0) {return;}// 如果itemsList还不存在if (itemsList == null || itemsList.Count == 0) {if(itemsList == null){itemsList = new List<LoopItemObject> ();}LoopItemObject item = GetItemFromLoop ();if(moveToEnd){InitItem (item, datasList.Count-1, datasList[datasList.Count-1]);}else{InitItem (item, 0, datasList[0]);}firstItem = lastItem = item;itemsList.Add (item);}bool all_invisible = true;for (int i = 0; i < itemsList.Count; i++) {if (itemsList[i].widget.isVisible == true) {all_invisible = false;}}if (all_invisible == true)return;// 先判断前端是否要增减if (firstItem.widget.isVisible) {// 判断要不要在它的前面补充一个itemif (firstItem.dataIndex > 0) {LoopItemObject item = GetItemFromLoop ();// 初化:数据索引、大小、位置、显示int index = firstItem.dataIndex - 1;//InitItem(item, index, datasList[index]);AddToFront (firstItem, item, index, datasList [index]);firstItem = item;itemsList.Insert (0, item);}} else {// 判断要不要将它移除// 条件:自身是不可见的;且它后一个item也是不可见的(或被被裁剪过半的).// 这有个隐含条件是itemsList.Count>=2.if (itemsList.Count >= 2&& itemsList [0].widget.isVisible == false&& itemsList [1].widget.isVisible == false) {itemsList.Remove (firstItem);PutItemToLoop (firstItem);firstItem = itemsList [0];}}// 再判断后端是否要增减if (lastItem.widget.isVisible) {// 判断要不要在它的后面补充一个itemif (lastItem.dataIndex < datasList.Count - 1) {LoopItemObject item = GetItemFromLoop ();// 初化:数据索引、大小、位置、显示int index = lastItem.dataIndex + 1;AddToBack (lastItem, item, index, datasList [index]);lastItem = item;itemsList.Add (item);}} else {// 判断要不要将它移除// 条件:自身是不可见的;且它前一个item也是不可见的(或被被裁剪过半的).// 这有个隐含条件是itemsList.Count>=2.if (itemsList.Count >= 2&& itemsList [itemsList.Count - 1].widget.isVisible == false&& itemsList [itemsList.Count - 2].widget.isVisible == false) {itemsList.Remove (lastItem);PutItemToLoop (lastItem);lastItem = itemsList [itemsList.Count - 1];}}}/// <summary>/// Init the specified datas./// </summary>/// <param name="datas">Datas.</param>public void Init (List<object> datas, DelegateHandler onItemInitCallback, bool moveToEnd = false){Reset();datasList = datas;this.OnItemInit = onItemInitCallback;Validate(moveToEnd);if(moveToEnd){MoveToEnd();}}/// <summary>/// 构造一个 item 对象/// </summary>/// <returns>The item.</returns>LoopItemObject CreateItem (){GameObject go = NGUITools.AddChild (itemParent, itemPrefab);UIWidget widget = go.GetComponent<UIWidget> ();LoopItemObject item = new LoopItemObject ();item.widget = widget;go.SetActive (true);return item;}/// <summary>/// 用数据列表来初始化scrollview/// </summary>/// <param name="item">Item.</param>/// <param name="indexData">Index data.</param>/// <param name="data">Data.</param>void InitItem (LoopItemObject item, int dataIndex, object data){item.dataIndex = dataIndex;if (OnItemInit != null) {OnItemInit (item, data);}item.widget.transform.localPosition = itemStartPos;}/// <summary>/// 在itemsList前面补上一个item/// </summary>void AddToFront (LoopItemObject priorItem, LoopItemObject newItem, int newIndex, object newData){InitItem (newItem, newIndex, newData);// 计算新item的位置if (scrollView.movement == UIScrollView.Movement.Vertical) {float offsetY = priorItem.widget.height * 0.5f + gapDis + newItem.widget.height * 0.5f;if (arrangeDirection == ArrangeDirection.Down_to_Up)offsetY *= -1f;newItem.widget.transform.localPosition = priorItem.widget.cachedTransform.localPosition + new Vector3 (0f, offsetY, 0f);} else {float offsetX = priorItem.widget.width * 0.5f + gapDis + newItem.widget.width * 0.5f;if (arrangeDirection == ArrangeDirection.Right_to_Left)offsetX *= -1f;newItem.widget.transform.localPosition = priorItem.widget.cachedTransform.localPosition - new Vector3 (offsetX, 0f, 0f);}}/// <summary>/// 在itemsList后面补上一个item/// </summary>void AddToBack (LoopItemObject backItem, LoopItemObject newItem, int newIndex, object newData){InitItem (newItem, newIndex, newData);// 计算新item的位置if (scrollView.movement == UIScrollView.Movement.Vertical) {float offsetY = backItem.widget.height * 0.5f + gapDis + newItem.widget.height * 0.5f;if (arrangeDirection == ArrangeDirection.Down_to_Up)offsetY *= -1f;newItem.widget.transform.localPosition = backItem.widget.cachedTransform.localPosition - new Vector3 (0f, offsetY, 0f);} else {float offsetX = backItem.widget.width * 0.5f + gapDis + newItem.widget.width * 0.5f;if (arrangeDirection == ArrangeDirection.Right_to_Left)offsetX *= -1f;newItem.widget.transform.localPosition = backItem.widget.cachedTransform.localPosition + new Vector3 (offsetX, 0f, 0f);}}public void AddItem(object data){if(datasList == null){datasList = new List<object>();}int dataIndex = datasList.Count;datasList.Add(data);if(scrollView != null && scrollView.panel != null && scrollView.panel.IsVisible(lastItem.widget)){LoopItemObject item = GetItemFromLoop();// 初化:数据索引、大小、位置、显示int index = lastItem.dataIndex + 1;AddToBack (lastItem, item, index, datasList[index]);lastItem = item;itemsList.Add(item);MoveToEnd();}}public void MoveToEnd(){if(scrollView == null){return;}UIWidget.Pivot pivot = UIWidget.Pivot.Bottom;if(scrollView.movement == UIScrollView.Movement.Horizontal){pivot = UIWidget.Pivot.Right;}var pivotCache = scrollView.contentPivot;scrollView.contentPivot = pivot;scrollView.ResetPosition();scrollView.contentPivot = pivotCache;}public void Reset(){if(itemsList == null || datasList == null){return;}for (int i = 0; i < itemsList.Count; i++) {PutItemToLoop(itemsList[i]);}itemsList.Clear();datasList.Clear();}#region 对象池性能相关/// <summary>/// 从对象池中取行一个item/// </summary>/// <returns>The item from loop.</returns>LoopItemObject GetItemFromLoop (){LoopItemObject item;if (itemLoop.Count <= 0) {item = CreateItem ();} else {item = itemLoop.Dequeue ();}item.widget.gameObject.SetActive (true);return item;}/// <summary>/// 将要移除的item放入对象池中/// --这个里我保证这个对象池中存在的对象不超过3个/// </summary>/// <param name="item">Item.</param>void PutItemToLoop (LoopItemObject item){if (itemLoop.Count >= maxPoolItem) {Destroy (item.widget.gameObject);return;}item.dataIndex = -1;item.widget.gameObject.SetActive (false);itemLoop.Enqueue (item);}#endregion}

using UnityEngine;using System.Collections;/// <summary>/// item对像的封装类Lzh_LoopItemObject,不要求具体的item类来继承它。/// 但我们要示具体的item对像一定要包含UIWidget组件。/// </summary>[System.Serializable]public class LoopItemObject{/// <summary>/// The widget./// </summary>public UIWidget widget;/// <summary>/// 本item,在实际整个scrollview中的索引位置,/// 即对就数据,在数据列表中的索引/// </summary>public int dataIndex= -1;}


0 0