• NGUI实现的一套不同大小 Item 的循环滚动代码


    测试:

    数据 & Item  的 Ctrl :

     1 using UnityEngine;
     2 
     3 public class ScrollViewItemData
     4 {
     5     public int index;
     6     public string name;
     7     public ScrollViewItemData(int index, string name)
     8     {
     9         this.index = index;
    10         this.name = name;
    11     }
    12 }
    13 
    14 
    15 public class ScrollViewItem : MonoBehaviour
    16 {
    17     UISprite sprBG;
    18     UILabel label;
    19     public ScrollViewItemData data;
    20 
    21     void Awake()
    22     {
    23         sprBG = GetComponent<UISprite>();
    24         label = transform.Find("Label").GetComponent<UILabel>();
    25     }
    26 
    27     public Vector3 BgSize
    28     {
    29         get
    30         {
    31             if (null != sprBG)
    32                 return sprBG.localSize;
    33             return Vector3.zero;
    34         }
    35 
    36     }
    37 
    38     public int BgHeigth
    39     {
    40         get
    41         {
    42             if (null != sprBG)
    43                 return sprBG.height;
    44             return 0;
    45         }
    46     }
    47 
    48     public void SetData(ScrollViewItemData data, int index)
    49     {
    50         this.data = data;
    51         label.text = data.name;
    52         sprBG.Update();
    53         //sprBG.ForceUpdate();
    54         this.gameObject.name = index.ToString();
    55     }
    56 }

    Item 大小一致的实现代码:

    using System.Collections.Generic;
    using UnityEngine;
    
    public class ScrollViewManager : MonoBehaviour
    {
        [SerializeField]
        GameObject itemPrefab;
    
        List<ScrollViewItem> itemList = new List<ScrollViewItem>();
        List<ScrollViewItemData> itemDataList = new List<ScrollViewItemData>();
    
        UIScrollView sv;
        UIGrid grid;
    
        //记录scrollviet上一次的位置,用于判断scrollview的移动方向
        float svLastPos = 0;
    
        //最大y坐标
        float maxHeight = 0;
    
        //最小y坐标
        float minHeight = 0;
    
        // Use this for initialization
        void Start()
        {
            //初始化测试数据
    
            for (int i = 0; i < 50; i++)
            {
                itemDataList.Add(new ScrollViewItemData(i, "" + (i + 1) + " 个元素"));
            }
    
    
            sv = transform.GetComponent<UIScrollView>();
            grid = transform.Find("Grid").GetComponent<UIGrid>();
    
            Vector2 viewsize = transform.GetComponent<UIPanel>().GetViewSize();
            int count = (int)(viewsize.y / grid.cellHeight + 2);
            Debug.Log(count);
            for (int i = 0; i < count; i++)
            {
                if (itemDataList.Count <= i)
                    break;
    
                GameObject obj = NGUITools.AddChild(grid.gameObject, itemPrefab);
    
                ScrollViewItem item = obj.GetComponent<ScrollViewItem>();
                itemList.Add(item);
    
                item.SetData(itemDataList[i], i);
            }
            grid.repositionNow = true;
            grid.Reposition();
    
            svLastPos = grid.transform.localPosition.y;
    
            maxHeight = viewsize.y / 2 + grid.cellHeight / 2;
    
            minHeight = -maxHeight;
    
            itemPrefab.SetActive(false);
    
        }
    
        // Update is called once per frame
        void Update()
        {
            float moveDis = sv.transform.localPosition.y - svLastPos;
            if (Mathf.Abs(moveDis) > 0.05)
            {
                bool isup = moveDis > 0;
                if (isup)
                {
                    while (itemList[0].transform.localPosition.y + sv.transform.localPosition.y > maxHeight &&
                           itemList[itemList.Count - 1].data.index < itemDataList.Count - 1)
                    {
                        ScrollViewItem item = itemList[0];
                        item.SetData(itemDataList[itemList[itemList.Count - 1].data.index + 1], item.data.index);
    
                        itemList.Add(item);
                        itemList.RemoveAt(0);
    
                        item.transform.localPosition = itemList[itemList.Count - 2].transform.localPosition - new Vector3(0, grid.cellHeight, 0);
                    }
                }
                else
                {
                    while (itemList[itemList.Count - 1].transform.localPosition.y + sv.transform.localPosition.y < minHeight &&
                        itemList[0].data.index > 0)
                    {
                        ScrollViewItem item = itemList[itemList.Count - 1];
                        item.SetData(itemDataList[itemList[0].data.index - 1], item.data.index);
    
                        itemList.Insert(0, item);
                        itemList.RemoveAt(itemList.Count - 1);
    
                        item.transform.localPosition = itemList[1].transform.localPosition + new Vector3(0, grid.cellHeight, 0);
                    }
                }
    
                svLastPos = sv.transform.localPosition.y;
            }
        }
    }

    Item 大小不一致的代码实现:

      1 using System;
      2 using System.Collections;
      3 using System.Collections.Generic;
      4 using System.Text;
      5 using UnityEngine;
      6 
      7 public class GUIScrollViewManager : MonoBehaviour
      8 {
      9     [SerializeField]
     10     GameObject itemPrefab;
     11 
     12     List<ScrollViewItem> itemList = new List<ScrollViewItem>();
     13     List<ScrollViewItemData> itemDataList = new List<ScrollViewItemData>();
     14     List<String> strList = new List<string>();
     15 
     16     UIScrollView sv;
     17     UITable table;
     18 
     19     //记录scrollviet上一次的位置,用于判断scrollview的移动方向
     20     float svLastPos = 0;
     21 
     22     //最大y坐标
     23     float maxHeight = 288.0f;
     24 
     25     //最小y坐标
     26     float minHeight = -288.0f;
     27 
     28     const string tmpStr = "初始化测试数据";
     29     const int Count = 50;
     30 
     31     // Use this for initialization
     32     void Start()
     33     {
     34         //初始化测试数据
     35         System.Random random = new System.Random();
     36         StringBuilder sb = new StringBuilder();
     37 
     38         int sbCounter = 0;
     39         for (int i = 0; i < Count; i++)
     40         {
     41             int tmpCount = random.Next(3, 15);
     42             sbCounter = 0;
     43             while (sbCounter < tmpCount)
     44             {
     45                 ++sbCounter;
     46                 sb.Append(tmpStr);
     47             }
     48             itemDataList.Add(new ScrollViewItemData(i, "" + (i + 1) + " 个元素" + sb.ToString()));
     49             sb.Remove(0, sb.Length);
     50 
     51         }
     52 
     53         sv = transform.GetComponent<UIScrollView>();
     54         table = transform.Find("Table").GetComponent<UITable>();
     55 
     56         int count = 10;
     57         for (int i = 0; i < count; i++)
     58         {
     59             if (itemDataList.Count <= i)
     60                 break;
     61 
     62             GameObject obj = NGUITools.AddChild(table.gameObject, itemPrefab);
     63             ScrollViewItem item = obj.GetComponent<ScrollViewItem>();
     64             itemList.Add(item);
     65 
     66             item.SetData(itemDataList[i], i);
     67         }
     68 
     69         table.Reposition();
     70 
     71         itemPrefab.SetActive(false);
     72     }
     73 
     74     void Update()
     75     {
     76         float moveDis = sv.transform.localPosition.y - svLastPos;
     77 
     78         if (Mathf.Abs(moveDis) > 0.05)
     79         {
     80             bool isup = moveDis > 0;
     81             if (isup)
     82             {
     83                 float height = NGUIMath.CalculateRelativeWidgetBounds(itemList[0].transform).size.y;
     84                 while (itemList[0].transform.localPosition.y + sv.transform.localPosition.y - height > maxHeight &&
     85                        itemList[itemList.Count - 1].data.index < itemDataList.Count - 1)
     86                 {
     87                     ScrollViewItem item = itemList[0];
     88                     item.SetData(itemDataList[itemList[itemList.Count - 1].data.index + 1], item.data.index);
     89 
     90                     itemList.Add(item);
     91                     itemList.RemoveAt(0);
     92 
     93                     float _height = NGUIMath.CalculateRelativeWidgetBounds(itemList[itemList.Count - 2].transform).size.y;
     94                     item.transform.localPosition = itemList[itemList.Count - 2].transform.localPosition - new Vector3(0, _height + 4, 0);
     95                 }
     96             }
     97             else
     98             {
     99                 while (itemList[itemList.Count - 1].transform.localPosition.y + sv.transform.localPosition.y < minHeight &&
    100                     itemList[0].data.index > 0)
    101                 {
    102                     ScrollViewItem item = itemList[itemList.Count - 1];
    103                     item.SetData(itemDataList[itemList[0].data.index - 1], item.data.index);
    104 
    105                     itemList.Insert(0, item);
    106                     itemList.RemoveAt(itemList.Count - 1);
    107 
    108                     float _height = NGUIMath.CalculateRelativeWidgetBounds(item.transform).size.y;
    109                     item.transform.localPosition = itemList[1].transform.localPosition + new Vector3(0, _height + 4, 0);
    110                 }
    111 
    112             }
    113 
    114             svLastPos = sv.transform.localPosition.y;
    115         }
    116     }
    117 }

    以上两种情况下 Prefab 的结构如下:

    效果:

      

    具体到项目中的实现代码(只记录了大致逻辑,具体细节无记录):

      1 using ClientData;
      2 using Modules.UI;
      3 using System;
      4 using System.Collections.Generic;
      5 using UnityEngine;
      6 
      7 /// <summary>
      8 /// Item 大小可变的动态循环列表实现(只支持竖向,暂且未实现对横向的支持)
      9 /// 该脚本需要挂在 UIScrollView  所在的 gameObject 上
     10 /// </summary>
     11 public class DynamicFlexibleSizeScrollView : MonoBehaviour
     12 {
     13     //定义的一些 delegate 为了,实现组件的通用化,把逻辑的实现下放到具体的实例中
     14     public delegate void OnInitItem(DFSItemCtrl item, DFSItemData data);
     15     public delegate void OnHideAllItem(List<DFSItemCtrl> itemList);
     16     public delegate DFSItemCtrl OnGetItemCtrl();
     17     public delegate void OnRecycleAllChatInfoCell(List<DFSItemCtrl> list);
     18 
     19 
     20     [SerializeField]
     21     Vector2 originalPanelClipOffset = new Vector2(0, 0);
     22     [SerializeField]
     23     Vector3 originalPanelPosition = new Vector3(0, 0, 0);
     24     [SerializeField]
     25     Vector3 originalTablePosition = new Vector3(0, 0, 0);
     26     [SerializeField]
     27     float maxHeight;        //最大y坐标
     28     [SerializeField]
     29     float minHeight;        //最小y坐标
     30     [SerializeField]
     31     int itemCount = 10;     //创建多少数量的 item 来做循环滚动
     32     [SerializeField]
     33     float offset = 6.0f;    //item 中间空出的距离
     34 
     35     float svLastPos = 0;        //记录scrollviet上一次的位置,用于判断scrollview的移动方向
     36     List<DFSItemCtrl> itemList = new List<DFSItemCtrl>();
     37     List<DFSItemData> itemDataList = new List<DFSItemData>();
     38     UIScrollView sv;
     39     UIPanel currUIPanel;
     40     UITable table;            //只是在初始化的时候会用到,在滑动的时候,不会再次操作该组件
     41 
     42     void InitNGUIComponent()
     43     {
     44         if (null == sv)
     45             sv = GetComponent<UIScrollView>();
     46 
     47         if (null != sv && null == currUIPanel)
     48             currUIPanel = sv.panel;
     49 
     50         if (null == table)
     51             table = GetComponentInChildren<UITable>();
     52     }
     53 
     54     public float MaxHeight
     55     {
     56         set { maxHeight = value; }
     57     }
     58 
     59     public float MinHeight
     60     {
     61         set { minHeight = value; }
     62     }
     63 
     64     public OnInitItem onInitItem;   //刷新 item
     65     public OnHideAllItem onHideAllItem;  //隐藏所有 item
     66 
     67     public OnGetItemCtrl getItemCtrl;
     68     public OnRecycleAllChatInfoCell recycleAllChatInfoCell;
     69 
     70 
     71     bool CheckContainData(DFSItemData data)
     72     {
     73         if (null != data)
     74         {
     75             for (int i = 0, iMax = itemDataList.Count - 1; i <= iMax; ++i)
     76             {
     77                 if (itemDataList[i].Index == data.Index)
     78                     return true;
     79             }
     80         }
     81 
     82         return false;
     83     }
     84 
     85     void AddData(DFSItemData data)
     86     {
     87         if (!CheckContainData(data))
     88         {
     89             itemDataList.Add(data);
     90         }
     91     }
     92 
     93     DFSItemCtrl tmpCtrl = null;
     94     public void ShowSingleItem(DFSItemData data)
     95     {
     96         if (null == data) return;
     97 
     98         InitNGUIComponent();
     99 
    100         AddData(data);
    101 
    102         if (itemList.Count < itemCount)
    103         {
    104             AddItem(data);
    105 
    106             if (null != table)
    107                 table.Reposition();
    108 
    109             if (null != sv)
    110                 sv.ResetPosition();
    111         }
    112         else
    113         {
    114             AutoDragUIPanelByData(data);
    115         }
    116     }
    117 
    118     void AutoDragUIPanelByData(DFSItemData data)
    119     {
    120         if (null != data)
    121         {
    122             if (null != getItemCtrl)
    123             {
    124                 //从池中拿出一个 item 计算 panel 需要移动的位置
    125                 if (null == tmpCtrl)
    126                     tmpCtrl = getItemCtrl();
    127 
    128                 if (null != tmpCtrl && null != onInitItem)
    129                 {
    130                     onInitItem(tmpCtrl, data);
    131                     float height = NGUIMath.CalculateRelativeWidgetBounds(tmpCtrl.transform).size.y;
    132                     Vector2 vec2 = new Vector2(0, height + offset);
    133                     SetPanelClipOff(vec2);
    134                     tmpCtrl.cachedGameObject.SetActive(false);
    135                 }
    136             }
    137         }
    138     }
    139 
    140     void SetPanelClipOff(Vector2 vec2)
    141     {
    142         Vector2 tmpOff = currUIPanel.clipOffset;
    143         tmpOff -= vec2;
    144         currUIPanel.clipOffset = tmpOff;
    145 
    146         Vector3 tmpPos = currUIPanel.cachedTransform.localPosition;
    147         tmpPos = new Vector3(tmpPos.x, -tmpOff.y, 0);
    148         currUIPanel.cachedTransform.localPosition = tmpPos;
    149     }
    150 
    151     public void ShowAllItems(List<DFSItemData> dataList)
    152     {
    153         if (null == dataList) return;
    154 
    155         svLastPos = 0;
    156         InitNGUIComponent();
    157 
    158         if (null != sv)
    159         {
    160             currUIPanel.clipOffset = originalPanelClipOffset;
    161             sv.transform.localPosition = originalPanelPosition;
    162         }
    163         if (null != table)
    164             table.transform.localPosition = originalTablePosition;
    165 
    166         //数据保存
    167         for (int i = 0, iMax = dataList.Count; i < iMax; ++i)
    168             AddData(dataList[i]);
    169 
    170 
    171         //如果数据数量大于了创建的item数量,自动滑动panel
    172         if (itemDataList.Count > itemCount)
    173         {
    174             int i = itemDataList.Count - itemCount,
    175                 iMax = itemDataList.Count;
    176             for (; i < iMax; ++i)
    177             {
    178                 AddItem(itemDataList[i]);
    179             }
    180         }
    181         else
    182         {
    183             for (int i = 0; i < itemCount; ++i)
    184             {
    185                 if (itemDataList.Count <= i) break;
    186                 AddItem(itemDataList[i]);
    187             }
    188 
    189         }
    190 
    191         ResetPanelStatus();
    192     }
    193 
    194     void ResetPanelStatus()
    195     {
    196         if (null != table)
    197             table.Reposition();
    198         if (null != sv)
    199             sv.ResetPosition();
    200     }
    201 
    202     public void RecycleAllChatInfoCell()
    203     {
    204         if (null != recycleAllChatInfoCell)
    205             recycleAllChatInfoCell(itemList);
    206         itemDataList.Clear();
    207     }
    208 
    209     void AddItem(DFSItemData data)
    210     {
    211         DFSItemCtrl item = null;
    212         if (null != getItemCtrl)
    213             item = getItemCtrl();
    214 
    215         if (null != data && null != item && null != onInitItem)
    216         {
    217             this.itemList.Add(item);
    218             item.cachedTransform.parent = table.transform;
    219             onInitItem(item, data);
    220         }
    221     }
    222 
    223     void Update()
    224     {
    225         if (null == onInitItem || null == itemDataList || itemList.Count <= 0) return;
    226 
    227         float moveDis = sv.transform.localPosition.y - svLastPos;
    228 
    229         if (Mathf.Abs(moveDis) > 0.05)
    230         {
    231             bool isup = moveDis > 0;
    232             if (isup)
    233             {
    234                 float height = NGUIMath.CalculateRelativeWidgetBounds(itemList[0].transform).size.y;
    235                 while (itemList[0].transform.localPosition.y + sv.transform.localPosition.y - height > maxHeight &&
    236                        itemList[itemList.Count - 1].Data.Index < itemDataList.Count - 1)
    237                 {
    238                     DFSItemCtrl item = itemList[0];
    239                     DFSItemData data = itemDataList[itemList[itemList.Count - 1].Data.Index + 1];
    240                     onInitItem(item, data);
    241 
    242                     itemList.Add(item);
    243                     itemList.RemoveAt(0);
    244 
    245                     float _height = NGUIMath.CalculateRelativeWidgetBounds(itemList[itemList.Count - 2].transform).size.y;
    246                     item.transform.localPosition = itemList[itemList.Count - 2].transform.localPosition - new Vector3(0, _height + offset, 0);
    247                 }
    248             }
    249             else
    250             {
    251                 while (itemList[itemList.Count - 1].transform.localPosition.y + sv.transform.localPosition.y < minHeight &&
    252                     itemList[0].Data.Index > 0)
    253                 {
    254                     DFSItemCtrl item = itemList[itemList.Count - 1];
    255                     DFSItemData data = itemDataList[itemList[0].Data.Index - 1];
    256                     onInitItem(item, data);
    257 
    258                     itemList.Insert(0, item);
    259                     itemList.RemoveAt(itemList.Count - 1);
    260 
    261                     float _height = NGUIMath.CalculateRelativeWidgetBounds(item.transform).size.y;
    262                     item.transform.localPosition = itemList[1].transform.localPosition + new Vector3(0, _height + offset, 0);
    263                 }
    264             }
    265 
    266             svLastPos = sv.transform.localPosition.y;
    267         }
    268     }
    269 }
    270 
    271 /// <summary>
    272 /// 列表中显示的 Item  ,应用到项目的时候,实际的 Item 可以继承自该类
    273 /// </summary>
    274 public class DFSItemCtrl : MonoBehaviour
    275 {
    276     protected DFSItemData data;
    277 
    278     public DFSItemData Data
    279     {
    280         get { return data; }
    281     }
    282 
    283     GameObject obj = null;
    284     public GameObject cachedGameObject
    285     {
    286         get
    287         {
    288             if (null == obj)
    289                 obj = gameObject;
    290             return obj;
    291         }
    292     }
    293 
    294     Transform tran = null;
    295     public Transform cachedTransform
    296     {
    297         get
    298         {
    299             if (null == tran)
    300                 tran = transform;
    301             return tran;
    302         }
    303     }
    304 
    305     public void ForceUpdateItemSize()
    306     {
    307 
    308     }
    309 
    310     public virtual void SetData(DFSItemData data,params UnityEngine.Object[] list)
    311     {
    312         if (null != data)
    313         {
    314             this.data = data;
    315             ChatInfo info = data as ChatInfo;
    316             this.cachedGameObject.name = info.Index.ToString();
    317         }
    318 
    319         //强制刷新一下 Item 的大小
    320         ForceUpdateItemSize();
    321     }
    322 }
    323 
    324 /// <summary>
    325 /// ItemData ,应用到项目的时候,实际的数据可以继承自该类
    326 /// </summary>
    327 public class DFSItemData
    328 {
    329     int index = -1;
    330 
    331     public virtual int Index
    332     {
    333         get { return index; }
    334         set { index = value; }
    335     }
    336 }

    效果:

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    Java面试题及解析
    Spring框架——IOC&DI
    Java项目开发流程()
    用户信息添加查重系统
    数据库对象——触发器、索引
    数据库对象——函数,视图,同义词,游标,包
  • 原文地址:https://www.cnblogs.com/luguoshuai/p/10214280.html
Copyright © 2020-2023  润新知