[Unity3d][NGUI]自写循环UIScrollView组件. 使用少量Item循环使用.



本组件根据四爷和Aklan的脚本为基础写的.

转载请注明出处:http://blog.csdn.net/zxsean/article/details/37386413


本组件使用时挂载在ScrollView下的Grid上即可.Item的数量只需要能覆盖一个页面的数量就可以了.


  1. using UnityEngine;  
  2. using System;  
  3. using System.Collections;  
  4. using System.Collections.Generic;  
  5.   
  6. /// <summary>  
  7. /// Loop循环ScrollView  
  8. /// 使用的时候挂载在ScrollView下面的UIGrid上就可以了  
  9. /// 然后UIGrid下面放置部分Item即可实现循环Item  
  10. /// </summary>  
  11. [RequireComponent(typeof(UIGrid))]  
  12. public class LoopScrollView_ZX : MonoBehaviour  
  13. {  
  14.     #region Members  
  15.   
  16.     /// <summary>  
  17.     /// 存储物件列表  
  18.     /// </summary>  
  19.     private List<UIWidget> m_itemList = new List<UIWidget>();  
  20.   
  21.     private Vector4 m_posParam;  
  22.     private Transform m_cachedTransform;  
  23.   
  24.     /// <summary>  
  25.     /// 起始下标  
  26.     /// </summary>  
  27.     private int m_startIndex;  
  28.     /// <summary>  
  29.     /// 最大长度  
  30.     /// </summary>  
  31.     private int m_MaxCount;  
  32.   
  33.     /// <summary>  
  34.     /// 物件刷新代理事件  
  35.     /// </summary>  
  36.     /// <param name="go"></param>  
  37.     public delegate void OnItemChange(GameObject go);  
  38.     private OnItemChange m_pItemChangeCallBack;  
  39.   
  40.     /// <summary>  
  41.     /// item点击代理事件  
  42.     /// </summary>  
  43.     /// <param name="go"></param>  
  44.     /// <param name="i"></param>  
  45.     public delegate void OnClickItem(GameObject go, int i);  
  46.     private OnClickItem m_pOnClickItemCallBack;  
  47.   
  48.     /// <summary>  
  49.     /// 父ScrollView  
  50.     /// </summary>  
  51.     public UIScrollView m_scrollView;  
  52.  
  53.     #endregion  
  54.   
  55.     void Awake()  
  56.     {  
  57.         m_cachedTransform = this.transform;  
  58.         m_scrollView = m_cachedTransform.parent.GetComponent<UIScrollView>();  
  59.   
  60.         // 设置Cull  
  61.         m_scrollView.GetComponent<UIPanel>().cullWhileDragging = true;  
  62.   
  63.         UIGrid _grid = this.GetComponent<UIGrid>();  
  64.         float _cellWidth = _grid.cellWidth;  
  65.         float _cellHeight = _grid.cellHeight;  
  66.         m_posParam = new Vector4(_cellWidth,  
  67.                                                     _cellHeight,  
  68.                                                     _grid.arrangement == UIGrid.Arrangement.Horizontal ? 1 : 0,  
  69.                                                     _grid.arrangement == UIGrid.Arrangement.Vertical ? 1 : 0);  
  70.     }  
  71.   
  72.     /// <summary>  
  73.     /// 初始化表  
  74.     /// </summary>  
  75.     public void Init(bool _clickItem)  
  76.     {  
  77.         m_itemList.Clear();  
  78.   
  79.         for (int i = 0; i < m_cachedTransform.childCount; ++i)  
  80.         {  
  81.             Transform _t = m_cachedTransform.GetChild(i);  
  82.             UIWidget uiW = _t.GetComponent<UIWidget>();  
  83.             if (uiW == null)  
  84.             {  
  85.                 uiW = _t.gameObject.AddComponent<UIWidget>();  
  86.             }  
  87.             uiW.name = m_itemList.Count.ToString();  
  88.             m_itemList.Add(uiW);  
  89.   
  90.             // 允许响应点击事件  
  91.             if (_clickItem)  
  92.             {  
  93.                 // 碰撞  
  94.                 BoxCollider _c = _t.GetComponent<BoxCollider>();  
  95.                 if (_c == null)  
  96.                 {  
  97.                     _c = _t.gameObject.AddComponent<BoxCollider>();  
  98.                     uiW.autoResizeBoxCollider = true;  
  99.                 }  
  100.   
  101.                 // 事件接收  
  102.                 UIEventListener _listener = _t.GetComponent<UIEventListener>();  
  103.                 if (_listener == null)  
  104.                 {  
  105.                     _listener = _t.gameObject.AddComponent<UIEventListener>();  
  106.                 }  
  107.   
  108.                 // 点击回调  
  109.                 _listener.onClick = OnClickListItem;  
  110.             }  
  111.         }  
  112.     }  
  113.   
  114.     /// <summary>  
  115.     /// 更新表单  
  116.     /// </summary>  
  117.     /// <param name="_count">数量</param>  
  118.     public void UpdateListItem(int _count)  
  119.     {  
  120.         m_startIndex = 0;  
  121.         m_MaxCount = _count;  
  122.   
  123.         for (int i = 0; i < m_itemList.Count; i++)  
  124.         {  
  125.             UIWidget _item = m_itemList[i];  
  126.             _item.name = i.ToString();  
  127.             _item.Invalidate(true);  
  128.   
  129.             NGUITools.SetActive(_item.gameObject, i < _count);  
  130.         }  
  131.     }  
  132.   
  133.     public List<UIWidget> GetItemList()  
  134.     {  
  135.         return m_itemList;  
  136.     }  
  137.   
  138.     public List<T> GetItemList<T>() where T : Component  
  139.     {  
  140.         List<T> _list = new List<T>();  
  141.   
  142.         foreach (UIWidget _wd in m_itemList)  
  143.         {  
  144.             _list.Add(_wd.GetComponent<T>());  
  145.         }  
  146.   
  147.         return _list;  
  148.     }  
  149.   
  150.     public List<T> GetItemListInChildren<T>() where T : Component  
  151.     {  
  152.         List<T> _list = new List<T>();  
  153.   
  154.         foreach (UIWidget _wd in m_itemList)  
  155.         {  
  156.             _list.Add(_wd.GetComponentInChildren<T>());  
  157.         }  
  158.   
  159.         return _list;  
  160.     }  
  161.   
  162.     void LateUpdate()  
  163.     {  
  164.         if (m_itemList.Count <= 1)  
  165.         {  
  166.             return;  
  167.         }  
  168.   
  169.         int _sourceIndex = -1;  
  170.         int _targetIndex = -1;  
  171.         int _sign = 0;  
  172.   
  173.         bool firstVislable = m_itemList[0].isVisible;  
  174.         bool lastVisiable = m_itemList[m_itemList.Count - 1].isVisible;  
  175.   
  176.         // 如果都显示,那么返回  
  177.         if (firstVislable == lastVisiable)  
  178.         {  
  179.             return;  
  180.         }  
  181.   
  182.         // 得到需要替换的源和目标  
  183.         if (firstVislable)  
  184.         {  
  185.             _sourceIndex = m_itemList.Count - 1;  
  186.             _targetIndex = 0;  
  187.             _sign = 1;  
  188.         }  
  189.         else if (lastVisiable)  
  190.         {  
  191.             _sourceIndex = 0;  
  192.             _targetIndex = m_itemList.Count - 1;  
  193.             _sign = -1;  
  194.         }  
  195.   
  196.         // 如果小于真正的初始索引或大于真正的结束索引,返回  
  197.         int realSourceIndex = int.Parse(m_itemList[_sourceIndex].gameObject.name);  
  198.         int realTargetIndex = int.Parse(m_itemList[_targetIndex].gameObject.name);  
  199.   
  200.         if (realTargetIndex <= m_startIndex ||  
  201.             realTargetIndex >= (m_MaxCount - 1))  
  202.         {  
  203.             m_scrollView.restrictWithinPanel = true;  
  204.             return;  
  205.         }  
  206.   
  207.         m_scrollView.restrictWithinPanel = false;  
  208.         UIWidget movedWidget = m_itemList[_sourceIndex];  
  209.   
  210.         Vector3 _offset = new Vector2(_sign * m_posParam.x * m_posParam.z,  
  211.                                                        _sign * m_posParam.y * m_posParam.w);  
  212.   
  213.         movedWidget.cachedTransform.localPosition = m_itemList[_targetIndex].cachedTransform.localPosition + _offset;  
  214.   
  215.         m_itemList.RemoveAt(_sourceIndex);  
  216.         m_itemList.Insert(_targetIndex, movedWidget);  
  217.         movedWidget.name = (realSourceIndex > realTargetIndex ? (realTargetIndex - 1) : (realTargetIndex + 1)).ToString();  
  218.   
  219.         OnItemChangeMsg(movedWidget.gameObject);  
  220.     }  
  221.   
  222.     /// <summary>  
  223.     /// 设置代理  
  224.     /// </summary>  
  225.     /// <param name="_onItemChange"></param>  
  226.     /// <param name="_onClickItem"></param>  
  227.     public void SetDelegate(OnItemChange _onItemChange,  
  228.                                          OnClickItem _onClickItem)  
  229.     {  
  230.         m_pItemChangeCallBack = _onItemChange;  
  231.   
  232.         if (_onClickItem != null)  
  233.         {  
  234.             m_pOnClickItemCallBack = _onClickItem;  
  235.         }  
  236.     }  
  237.   
  238.     void OnItemChangeMsg(GameObject go)  
  239.     {  
  240.         if (m_pItemChangeCallBack != null)  
  241.         {  
  242.             m_pItemChangeCallBack(go);  
  243.         }  
  244.     }  
  245.   
  246.     void OnClickListItem(GameObject go)  
  247.     {  
  248.         int _i = int.Parse(go.name);  
  249.   
  250.         if (m_pOnClickItemCallBack != null)  
  251.         {  
  252.             m_pOnClickItemCallBack(go, _i);  
  253.         }  
  254.     }  
  255. }  
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// Loop循环ScrollView
/// 使用的时候挂载在ScrollView下面的UIGrid上就可以了
/// 然后UIGrid下面放置部分Item即可实现循环Item
/// </summary>
[RequireComponent(typeof(UIGrid))]
public class LoopScrollView_ZX : MonoBehaviour
{
    #region Members

    /// <summary>
    /// 存储物件列表
    /// </summary>
    private List<UIWidget> m_itemList = new List<UIWidget>();

    private Vector4 m_posParam;
    private Transform m_cachedTransform;

    /// <summary>
    /// 起始下标
    /// </summary>
    private int m_startIndex;
    /// <summary>
    /// 最大长度
    /// </summary>
    private int m_MaxCount;

    /// <summary>
    /// 物件刷新代理事件
    /// </summary>
    /// <param name="go"></param>
    public delegate void OnItemChange(GameObject go);
    private OnItemChange m_pItemChangeCallBack;

    /// <summary>
    /// item点击代理事件
    /// </summary>
    /// <param name="go"></param>
    /// <param name="i"></param>
    public delegate void OnClickItem(GameObject go, int i);
    private OnClickItem m_pOnClickItemCallBack;

    /// <summary>
    /// 父ScrollView
    /// </summary>
    public UIScrollView m_scrollView;

    #endregion

    void Awake()
    {
        m_cachedTransform = this.transform;
        m_scrollView = m_cachedTransform.parent.GetComponent<UIScrollView>();

        // 设置Cull
        m_scrollView.GetComponent<UIPanel>().cullWhileDragging = true;

        UIGrid _grid = this.GetComponent<UIGrid>();
        float _cellWidth = _grid.cellWidth;
        float _cellHeight = _grid.cellHeight;
        m_posParam = new Vector4(_cellWidth,
                                                    _cellHeight,
                                                    _grid.arrangement == UIGrid.Arrangement.Horizontal ? 1 : 0,
                                                    _grid.arrangement == UIGrid.Arrangement.Vertical ? 1 : 0);
    }

    /// <summary>
    /// 初始化表
    /// </summary>
    public void Init(bool _clickItem)
    {
        m_itemList.Clear();

        for (int i = 0; i < m_cachedTransform.childCount; ++i)
        {
            Transform _t = m_cachedTransform.GetChild(i);
            UIWidget uiW = _t.GetComponent<UIWidget>();
            if (uiW == null)
            {
                uiW = _t.gameObject.AddComponent<UIWidget>();
            }
            uiW.name = m_itemList.Count.ToString();
            m_itemList.Add(uiW);

            // 允许响应点击事件
            if (_clickItem)
            {
                // 碰撞
                BoxCollider _c = _t.GetComponent<BoxCollider>();
                if (_c == null)
                {
                    _c = _t.gameObject.AddComponent<BoxCollider>();
                    uiW.autoResizeBoxCollider = true;
                }

                // 事件接收
                UIEventListener _listener = _t.GetComponent<UIEventListener>();
                if (_listener == null)
                {
                    _listener = _t.gameObject.AddComponent<UIEventListener>();
                }

                // 点击回调
                _listener.onClick = OnClickListItem;
            }
        }
    }

    /// <summary>
    /// 更新表单
    /// </summary>
    /// <param name="_count">数量</param>
    public void UpdateListItem(int _count)
    {
        m_startIndex = 0;
        m_MaxCount = _count;

        for (int i = 0; i < m_itemList.Count; i++)
        {
            UIWidget _item = m_itemList[i];
            _item.name = i.ToString();
            _item.Invalidate(true);

            NGUITools.SetActive(_item.gameObject, i < _count);
        }
    }

    public List<UIWidget> GetItemList()
    {
        return m_itemList;
    }

    public List<T> GetItemList<T>() where T : Component
    {
        List<T> _list = new List<T>();

        foreach (UIWidget _wd in m_itemList)
        {
            _list.Add(_wd.GetComponent<T>());
        }

        return _list;
    }

    public List<T> GetItemListInChildren<T>() where T : Component
    {
        List<T> _list = new List<T>();

        foreach (UIWidget _wd in m_itemList)
        {
            _list.Add(_wd.GetComponentInChildren<T>());
        }

        return _list;
    }

    void LateUpdate()
    {
        if (m_itemList.Count <= 1)
        {
            return;
        }

        int _sourceIndex = -1;
        int _targetIndex = -1;
        int _sign = 0;

        bool firstVislable = m_itemList[0].isVisible;
        bool lastVisiable = m_itemList[m_itemList.Count - 1].isVisible;

        // 如果都显示,那么返回
        if (firstVislable == lastVisiable)
        {
            return;
        }

        // 得到需要替换的源和目标
        if (firstVislable)
        {
            _sourceIndex = m_itemList.Count - 1;
            _targetIndex = 0;
            _sign = 1;
        }
        else if (lastVisiable)
        {
            _sourceIndex = 0;
            _targetIndex = m_itemList.Count - 1;
            _sign = -1;
        }

        // 如果小于真正的初始索引或大于真正的结束索引,返回
        int realSourceIndex = int.Parse(m_itemList[_sourceIndex].gameObject.name);
        int realTargetIndex = int.Parse(m_itemList[_targetIndex].gameObject.name);

        if (realTargetIndex <= m_startIndex ||
            realTargetIndex >= (m_MaxCount - 1))
        {
            m_scrollView.restrictWithinPanel = true;
            return;
        }

        m_scrollView.restrictWithinPanel = false;
        UIWidget movedWidget = m_itemList[_sourceIndex];

        Vector3 _offset = new Vector2(_sign * m_posParam.x * m_posParam.z,
                                                       _sign * m_posParam.y * m_posParam.w);

        movedWidget.cachedTransform.localPosition = m_itemList[_targetIndex].cachedTransform.localPosition + _offset;

        m_itemList.RemoveAt(_sourceIndex);
        m_itemList.Insert(_targetIndex, movedWidget);
        movedWidget.name = (realSourceIndex > realTargetIndex ? (realTargetIndex - 1) : (realTargetIndex + 1)).ToString();

        OnItemChangeMsg(movedWidget.gameObject);
    }

    /// <summary>
    /// 设置代理
    /// </summary>
    /// <param name="_onItemChange"></param>
    /// <param name="_onClickItem"></param>
    public void SetDelegate(OnItemChange _onItemChange,
                                         OnClickItem _onClickItem)
    {
        m_pItemChangeCallBack = _onItemChange;

        if (_onClickItem != null)
        {
            m_pOnClickItemCallBack = _onClickItem;
        }
    }

    void OnItemChangeMsg(GameObject go)
    {
        if (m_pItemChangeCallBack != null)
        {
            m_pItemChangeCallBack(go);
        }
    }

    void OnClickListItem(GameObject go)
    {
        int _i = int.Parse(go.name);

        if (m_pOnClickItemCallBack != null)
        {
            m_pOnClickItemCallBack(go, _i);
        }
    }
}

测试脚本.挂载在Grid上即可.

  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. /// <summary>  
  5. /// 测试脚本  
  6. /// </summary>  
  7. public class Test : MonoBehaviour  
  8. {  
  9.     LoopScrollView_ZX m_scrollView;  
  10.   
  11.     void Start()  
  12.     {  
  13.         m_scrollView = this.GetComponent<LoopScrollView_ZX>();  
  14.         m_scrollView.Init(true);  
  15.         m_scrollView.UpdateListItem(100);  
  16.         m_scrollView.SetDelegate(null, OnClickTest);  
  17.     }  
  18.   
  19.     /// <summary>  
  20.     /// 点击事件  
  21.     /// </summary>  
  22.     /// <param name="go"></param>  
  23.     /// <param name="i"></param>  
  24.     void OnClickTest(GameObject go, int i)  
  25.     {  
  26.         Debug.Log(go.name + "," + i);  
  27.     }  
  28. }  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值