1. 程式人生 > >無限滾動UI面板

無限滾動UI面板

using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class Mall
{
    public Sprite sprite;//貼圖
    public string ModelName = "";//模型名字
    public string GoodsMessage = "";//物品介紹
    //toto
}
public class UILoopListEzample : MonoBehaviour
{
    public int ItemAmount;
    public UILoopList uiList;
    // Use this for initialization
    void Start()
    {
        uiList.onSelectedEvent = OnSelectedEventHandler;
        List<int> listData = new List<int>();
        for (int i = 0; i < ItemAmount; i++)
        {
            listData.Add(i);
        }
        uiList.Data(listData);
    }

    private void OnSelectedEventHandler(UILoopItem item)
    {
        Debug.LogError("選擇的單元資料為:" + item.GetData().ToString());
    }
    
}

------------------------------------======================-------------------------------
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class UILoopItem : MonoBehaviour
{
    [System.NonSerialized]
    public int itemIndex;//當前資料第幾個
    [System.NonSerialized]
    public GameObject itemObject;
    private object data;
    private Mall Mall_;
    public void UpdateItem(int index, GameObject item)//(object mall,int index, GameObject item)
    {
        itemIndex = index;
        itemObject = item;

    }
 
    public virtual void Data(object data)
    {
        this.data = data;
        transform.Find("Text").GetComponent<Text>().text = "資料" + data.ToString();
    }
    public virtual object GetData()
    {
        return data;
    }
    public virtual void SetSelected(bool selected)
    {

    }
}
----------------------------------========================-------------------------------
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;

public class UILoopList : MonoBehaviour
{
    /// <summary>
    /// 滾動的方向
    /// </summary>
    enum Direction
    {
        Horizontal,//水平方向
        Vertical//垂直方向
    }
    /// <summary>
    /// 離上邊的距離
    /// </summary>
    [SerializeField]
    private float topPadding = 0;
    /// <summary>
    /// 離下邊的距離
    /// </summary>
    [SerializeField]
    private float bottomPadding = 0;
    /// <summary>
    ///time框
    /// </summary>
    [SerializeField]
    private RectTransform m_Cell;
    [SerializeField]
    private Vector2 m_Page = new Vector2(1, 1);//必須設定;幾行幾列
    [SerializeField]
    Direction direction = Direction.Horizontal;
    [SerializeField, Range(4, 10)]
    private int m_BufferNo;//Item的數量
    /// <summary>
    /// Item的間隔
    /// </summary>
    [SerializeField]
    private float cellGapX = 0f;
    [SerializeField]
    private float cellGapY = 0f;
    public delegate void OnSelectedEvent(UILoopItem item);
    /// <summary>
    /// 選擇事件 但元件上一定要有Button元件 設定要在Data()設定資料前
    /// </summary>
    public OnSelectedEvent onSelectedEvent;//
    private List<RectTransform> m_InstantiateItems = new List<RectTransform>();
    private List<RectTransform> m_oldItems = new List<RectTransform>();
    /// <summary>
    /// Time的實際數量就是數字
    /// </summary>
    private IList m_Datas;
    /// <summary>
    /// 調整Item的間隔
    /// </summary>
    public Vector2 CellRect
    {
        get
        {
            return m_Cell != null ? new Vector2(cellGapX + m_Cell.sizeDelta.x, cellGapY + m_Cell.sizeDelta.y) : new Vector2(100, 100);
        }
    }
    /// <summary>
    /// 調整Item的間隔返回的是X 還是 Y
    /// </summary>
    public float CellScale { get { return direction == Direction.Horizontal ? CellRect.x : CellRect.y; } }
    private float m_PrevPos = 0;
    // 返回的是Content距離錨點的距離 x或y
    public float DirectionPos { get { return direction == Direction.Horizontal ? m_Rect.anchoredPosition.x : m_Rect.anchoredPosition.y; } }
    private int m_CurrentIndex;//頁面的第一行(列)在整個conten中的位置
    private Vector2 m_InstantiateSize = Vector2.zero;
    public Vector2 InstantiateSize
    {
        get
        {
            if (m_InstantiateSize == Vector2.zero)
            {
                float rows, cols;
                if (direction == Direction.Horizontal)
                {
                    rows = m_Page.x;
                    cols = m_Page.y + (float)m_BufferNo;
                }
                else
                {
                    rows = m_Page.x + (float)m_BufferNo;
                    cols = m_Page.y;
                }
                                    //            5      1
                m_InstantiateSize = new Vector2(rows, cols);
            }
            return m_InstantiateSize;
        }
    }
    /// <summary>
    /// 返回的是行數成於列數
    /// </summary>
    public int PageCount { get { return (int)m_Page.x * (int)m_Page.y; } }
    public int PageScale { get { return direction == Direction.Horizontal ? (int)m_Page.x : (int)m_Page.y; } }//返回的是幾行幾列
    private ScrollRect m_ScrollRect;
    private RectTransform m_Rect;
    public int InstantiateCount { get { return (int)InstantiateSize.x * (int)InstantiateSize.y; } }


    protected void Awake()
    {
        m_ScrollRect = GetComponentInParent<ScrollRect>();

        m_ScrollRect.horizontal = direction == Direction.Horizontal;//滾動方向是否是垂直
        m_ScrollRect.vertical = direction == Direction.Vertical;//滾動方向是否是水平

        m_Rect = GetComponent<RectTransform>();

        if (m_Cell.transform.parent != null)
            m_Cell.gameObject.SetActive(false);//隱藏第一個Item面板

        m_Rect.anchorMax = Vector2.zero;//設定中心點Content
        m_Rect.anchorMin = Vector2.zero;//設定錨點Content
        m_Rect.pivot = Vector2.zero;//它在這個RectTransform中旋轉的標準化位置。
        m_Rect.anchoredPosition = new Vector2(0f, 0f);//相對於錨點的位置設定為0,0
    }

    /// <summary>
    /// 設定資料 資料格式為IList
    /// </summary>
    /// <param name="data">Data.</param>
    public void Data(object data)
    {
        Reset();
        m_Datas = data as IList;
        if (m_Datas.Count > PageCount)//item數量是否大於 行成於列
        {
            //to
            setBound(getRectByNum(m_Datas.Count));//構建滑動框的大小
        }
        else
        {
            setBound(m_Page);
        }
        if (m_Datas.Count > InstantiateCount)//是否Item數量大於 tiem數量加上行的數量 
        {
            // print(m_Datas.Count+"  "+InstantiateCount );
            //toto
            while (m_InstantiateItems.Count < InstantiateCount)
            {
                createItem(m_InstantiateItems.Count);//在這裡生成的五個
            }
        }
        else
        {
            while (m_InstantiateItems.Count > m_Datas.Count)
            {
                removeItem(m_InstantiateItems.Count - 1);
            }
            while (m_InstantiateItems.Count < m_Datas.Count)
            {
                
                createItem(m_InstantiateItems.Count);
            }
        }
        if (m_Datas.Count > 0)
        {
            int count = Mathf.Min(m_InstantiateItems.Count, m_Datas.Count);
            for (int i = 0; i < count; i++)
            {
                updateItem(i, m_InstantiateItems[i].gameObject);
            }
        }
    }

    private void Reset()
    {

        for (int i = 0; i < m_InstantiateItems.Count; i++)
        {
            m_InstantiateItems[i].gameObject.SetActive(false);
            m_oldItems.Add(m_InstantiateItems[i]);
        }
        m_InstantiateItems.Clear();
        m_PrevPos = 0;
        m_CurrentIndex = 0;
        selectedObject = null;
        selectedItem = null;
        this.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, 0);
    }
    public void SetIndexToBottom(int itemIndex)
    {
        this.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, CellRect.y * itemIndex - m_ScrollRect.GetComponent<RectTransform>().sizeDelta.y + CellRect.y * 2 + topPadding + bottomPadding);
    }
    private void createItem(int index)//0
    {
        RectTransform item = null;
        if (m_oldItems.Count > 0)
        {
            item = m_oldItems[0];
            m_oldItems.Remove(item);
        }
        else
        {
            
            item = GameObject.Instantiate(m_Cell);
            item.SetParent(transform, false);
            item.anchorMax = Vector2.zero;
            item.anchorMin = Vector2.zero;
            item.pivot = Vector2.zero;
        }

        item.name = "item" + index;
        item.anchoredPosition = getPosByIndex(index);
       // print(getPosByIndex(index));
        m_InstantiateItems.Add(item);//新增進集合中
        item.gameObject.SetActive(true);
        //updateItem(index, item.gameObject);
    }
    private void removeItem(int index)
    {
        RectTransform item = m_InstantiateItems[index];
        m_InstantiateItems.Remove(item);
        item.gameObject.SetActive(false);
        m_oldItems.Add(item);
        //RectTransform.Destroy(item.gameObject);
    }
    /// <summary>
    /// 由格子數量獲取多少行多少列
    /// </summary>
    /// <param name="num"></param>格子個數
    /// <returns></returns>
    private Vector2 getRectByNum(int num)
    {
        return direction == Direction.Horizontal ?
            new Vector2(m_Page.x, Mathf.CeilToInt(num / m_Page.x)) :
                new Vector2(Mathf.CeilToInt(num / m_Page.y), m_Page.y);
    }
    /// <summary>
    /// 設定Content的大小
    /// </summary>
    /// <param name="rows"></param>行數
    /// <param name="cols"></param>列數
    private void setBound(Vector2 bound)
    {
       // Debug.Log(bound.y * CellRect.x+":X");Debug.Log(bound.x * CellRect.y + bottomPadding + topPadding + ":Y");
        m_Rect.sizeDelta = new Vector2(bound.y * CellRect.x, bound.x * CellRect.y + bottomPadding + topPadding);
    }
    public float MaxPrevPos
    {
        get
        {
            float result;
            Vector2 max = getRectByNum(m_Datas.Count);
            if (direction == Direction.Horizontal)
            {
                result = max.y - m_Page.y;
            }
            else
            {
                result = max.x - m_Page.x;
            }
            return result * CellScale;
        }
    }
    public float scale { get { return direction == Direction.Horizontal ? 1f : -1f; } }//是橫向就是1不是為-1
    private bool isFirst = true;
    void Update()
    {
        if (isFirst == true)
        {
            isFirst = false;
            return;
        }
        //1或-1 ×與 X或Y -0
        
        while (scale * DirectionPos - m_PrevPos < -CellScale * 2)
        {
            //Debug.Log(scale.ToString() + "  " + DirectionPos.ToString() + "  " + m_PrevPos.ToString() + "_____________" + -CellScale * 2);
            if (m_PrevPos <= -MaxPrevPos) return;
            m_PrevPos -= CellScale;
            List<RectTransform> range = m_InstantiateItems.GetRange(0, PageScale);
            m_InstantiateItems.RemoveRange(0, PageScale);
            m_InstantiateItems.AddRange(range);
            for (int i = 0; i < range.Count; i++)
            {
                moveItemToIndex(m_CurrentIndex * PageScale + m_InstantiateItems.Count + i, range[i]);
            }
            m_CurrentIndex++;
        }
        while (scale * DirectionPos - m_PrevPos > -CellScale)
        {
            //  Debug.Log(scale.ToString() + "  " + DirectionPos.ToString() + "  " + m_PrevPos.ToString() + "_____________" + -CellScale);

            if (Mathf.RoundToInt(m_PrevPos) >= 0) return;
            m_PrevPos += CellScale;
            m_CurrentIndex--;
            if (m_CurrentIndex < 0) return;
            List<RectTransform> range = m_InstantiateItems.GetRange(m_InstantiateItems.Count - PageScale, PageScale);
            m_InstantiateItems.RemoveRange(m_InstantiateItems.Count - PageScale, PageScale);
            m_InstantiateItems.InsertRange(0, range);
            for (int i = 0; i < range.Count; i++)
            {
                moveItemToIndex(m_CurrentIndex * PageScale + i, range[i]);
            }
        }
    }
    private void moveItemToIndex(int index, RectTransform item)
    {
        item.anchoredPosition = getPosByIndex(index);
        updateItem(index, item.gameObject);
    }
    /// <summary>
    /// 初始化間距位置
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    private Vector2 getPosByIndex(int index)
    {
        return direction == Direction.Horizontal ?
            new Vector2(Mathf.Floor(index / InstantiateSize.x) * CellRect.x, -(index % InstantiateSize.x) * CellRect.y) :
                new Vector2((index % InstantiateSize.y) * CellRect.x, -Mathf.Floor(index / InstantiateSize.y) * CellRect.y - topPadding);
        //float x, y;
        //if(direction == Direction.Horizontal)
        //{
        //    x = index % m_Page.x;
        //    y = Mathf.FloorToInt(index / m_Page.x);
        //}
        //else
        //{
        //    x = Mathf.FloorToInt(index / m_Page.y);
        //    y = index % m_Page.y;
        //}
        //return new Vector2(y * CellRect.x, -x * CellRect.y);
    }
    private object selectedObject = null;
    [System.NonSerialized]
    public UILoopItem selectedItem = null;
    private void updateItem(int index, GameObject item)
    {
        item.SetActive(index < m_Datas.Count);
        if (item.activeSelf)
        {
            UILoopItem lit = item.GetComponent<UILoopItem>();
            lit.UpdateItem(index, item);
            lit.Data(m_Datas[index]);//列印函式
            Debug.Log(selectedObject + "  666 " + m_Datas[index]);

            if (selectedObject == m_Datas[index])
            {
                lit.SetSelected(true);
            }
            else
            {
                lit.SetSelected(false);
            }
                                                                                                            //該BUtton在列表中的索引
            if (lit.GetComponent<Button>() != null && onSelectedEvent != null && addClickEventList.IndexOf(lit.GetComponent<Button>()) < 0)
            {
                addClickEventList.Add(lit.GetComponent<Button>());
                lit.GetComponent<Button>().onClick.AddListener(delegate ()
                {
                    if (onSelectedEvent != null)
                    {
                        if (selectedItem != null && selectedItem != item.GetComponent<UILoopItem>())
                        {
                            selectedItem.SetSelected(false);
                        }
                        selectedItem = item.GetComponent<UILoopItem>();
                        selectedObject = selectedItem.GetData();
                        selectedItem.SetSelected(true);
                        onSelectedEvent(selectedItem);
                    }
                });
            }
        }
    }
    private List<Button> addClickEventList = new List<Button>();
    /// <summary>
    /// 選中的物件
    /// </summary>
    /// <returns></returns>
    public object GetSelectedData()
    {
        return selectedObject;
    }
    /// <summary>
    /// 設定選中物件
    /// </summary>
    /// <param name="selectedIndex"></param>
    public void SetSelectedIndex(int selectedIndex)
    {
        if (m_Datas.Count > 0 && m_Datas.Count > selectedIndex)
        {
            selectedObject = m_Datas[selectedIndex];
            if (selectedItem != null)
            {
                selectedItem.SetSelected(false);
            }
            for (int i = 0; i < m_InstantiateItems.Count; i++)
            {
                if (selectedObject == m_InstantiateItems[i].GetComponent<UILoopItem>().GetData())
                {
                    m_InstantiateItems[i].GetComponent<UILoopItem>().SetSelected(true);
                    selectedItem = m_InstantiateItems[i].GetComponent<UILoopItem>();
                }
            }
        }
    }
}