Unity3D界面管理——无限列表(基于UGUI)

1.主要思路:

  1. 根据列表项的大小与可视框生成大于可视框一个数量的列表项
  2. 根据列表项距离可视框中间的距离进行上下切换(使用数据结构为链表)
  3. 根据滚动距离做累加,求得当前的索引值,并通过索引值获取对应数据对列表项赋值

 

验证:提供有边界和无边界两种虚拟列表

  1. 有边界的列表将会在临界值(0或者1000)无法向上一个索引值(0)或下一个索引值(1000)滚动
  2. 无边界的列表将会在临界值时进行循环滚动

列表:

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

/// <summary>
/// 虚拟列表
/// </summary>
public class VirtualList : MonoBehaviour, IScrollHandler
{
    /// <summary>
    /// 元件尺寸
    /// </summary>
    public Vector2 ItemSize;

    /// <summary>
    /// 放置内容
    /// </summary>
    public RectTransform Content;

    /// <summary>
    /// 列表项缓存
    /// </summary>
    private LinkedList<VirtualListItem> virtualListItems;

    public List<VirtualListItemData> DataList = new List<VirtualListItemData>();

    /// <summary>
    /// 列表单元预制体
    /// </summary>
    [SerializeField]
    private GameObject ListItemPrefab;

    /// <summary>
    /// 当前的中心二维坐标
    /// </summary>
    private Vector2 curCenterPos;

    /// <summary>
    /// 初始的中心二维坐标
    /// </summary>
    private Vector2 originCenterPos;

    /// <summary>
    /// 行数
    /// </summary>
    private uint VirtualRow;

    private Vector2 TopPos;

    private Vector2 LastPos;

    public uint CanViewNum;

    /// <summary>
    /// 每次的偏移量
    /// </summary>
    private Vector2 deltaPos;

    public bool HasEdge = true;

    public void Start()
    {
        curCenterPos.y += Content.rect.height / 2;
        LastPos.y = -200;
        Debug.Log(LastPos.y);
        originCenterPos.y = Content.rect.height / 2;
        VirtualRow = CanViewNum+1;
        TopPos.y =200;
        virtualListItems = new LinkedList<VirtualListItem>();
        InitData();
        for (int i = 0; i < VirtualRow; i++)
        {
            VirtualListItem temp = MonoBehaviour.Instantiate(ListItemPrefab, Content).GetComponent<VirtualListItem>();
            virtualListItems.AddLast(temp);
            temp.Init(this);
            temp.SetIndex(i, 1);
            temp.BindData(DataList[i]);
        }

    }

    public void InitData()
    {
        for(int i = 0; i < 1001; i++)
        {
            DataList.Add(new VirtualListItemData(i.ToString(),i));
        }
    }

    private void CalculatePosistion(VirtualListItem item)
    {
        float tempPosY = deltaPos.y + item.transform.localPosition.y;


        Vector3 tempPos = item.transform.localPosition;
        item.transform.localPosition = new Vector3(item.transform.localPosition.x, tempPosY,item.transform.localPosition.z);
        if (tempPosY < LastPos.y*1.5)
        {
            if (HasEdge&& virtualListItems.First.Value.Data.CurIndex - 1 < 0)
            {
                return;
            }
            int index = virtualListItems.First.Value.Data.CurIndex - 1;
            if (index < 0)
                index += DataList.Count;
            LinkedListNode<VirtualListItem> tempNode = virtualListItems.Last;
            tempNode.Value.transform.localPosition = new Vector3(virtualListItems.First.Value.transform.localPosition.x,
                virtualListItems.First.Value.transform.localPosition.y + item.SizeY,
                virtualListItems.First.Value.transform.localPosition.z);
            virtualListItems.RemoveLast();
            tempNode.Value.BindData(DataList[index]);
            virtualListItems.AddFirst(tempNode);
        }

        if (tempPosY > TopPos.y * 1.5)
        {
            if (HasEdge && virtualListItems.Last.Value.Data.CurIndex +1> DataList.Count - 1)
            {
                return;
            }
            int index = virtualListItems.Last.Value.Data.CurIndex + 1;
            if (index > DataList.Count - 1)
                index = index-(DataList.Count);

            LinkedListNode<VirtualListItem> tempNode = virtualListItems.First;
            tempNode.Value.transform.position = new Vector3(virtualListItems.Last.Value.transform.position.x,
                virtualListItems.Last.Value.transform.position.y - item.SizeY,
                virtualListItems.Last.Value.transform.position.z);
            virtualListItems.RemoveFirst();
            tempNode.Value.BindData(DataList[index]);
            virtualListItems.AddLast(tempNode);
        }

    }

    public void OnScroll(PointerEventData eventData)
    {
        deltaPos.y = eventData.scrollDelta.y*30;
        Debug.Log(deltaPos.y);
        LinkedListNode<VirtualListItem> node = virtualListItems.First;
        if (HasEdge)
        {
            if (virtualListItems.First.Value.TotalIndex == 0 && deltaPos.y < 0 && virtualListItems.First.Value.transform.localPosition.y < TopPos.y)
            {
                return;
            }
            if (virtualListItems.Last.Value.TotalIndex == DataList.Count - 1 && deltaPos.y > 0 && virtualListItems.Last.Value.transform.localPosition.y > LastPos.y - 30)
            {
                return;
            }
        }

        bool isForeachFinish = false;
        while (node != null && !isForeachFinish)
        {
            if (node == virtualListItems.Last)
            {
                isForeachFinish = true;
            }
            CalculatePosistion(node.Value);

            node = node.Next;
        }
    }
}

 

列表项:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class VirtualListItem : MonoBehaviour
{
    public VirtualList CurList;
    public float SizeY { get; private set; }

    public float SizeX { get; private set; }

    public int RowIndex { get; private set; }

    public int ColIndex { get; private set; }

    public int TotalIndex { get { return Data.CurIndex; } }

    [SerializeField]
    private RectTransform curRectTransform;

    public Text IndexText;

    public VirtualListItemData Data;

    public void Init(VirtualList list)
    {
        CurList = list;
        SizeY = curRectTransform.rect.height;
        SizeX = curRectTransform.rect.width;
    }

    public void SetIndex(int rowIndex, int colIndex)
    {
        RowIndex = rowIndex;
        ColIndex = colIndex;
        Debug.Log(CurList.Content.rect.y);
        curRectTransform.localPosition = new Vector2(0, -4*CurList.Content.rect.y/ CurList.CanViewNum - (rowIndex * SizeY));

    }

    public void SetContent(string content)
    {
        IndexText.text = content;
    }

    public void BindData(VirtualListItemData data)
    {
        this.Data = data;
        IndexText.text = data.Content.ToString();
    }
}

列表数据接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class VirtualListItemData 
{
    public object Content { get; set; }

    public int CurIndex { get; set; }

    public VirtualListItemData(object content,int index)
    {
        Content = content;
        CurIndex = index;
    }
}

 

工程:https://github.com/Markey007/VirtualList.git

 

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值