当前位置: 首页 > article >正文

Unity UGUI 垂直循环复用滚动

一 基础类 在unity里面新建这几个类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 垂直方向滚动
/// </summary>
public class CustomScroll:MonoBehaviour
{
    public ScrollRect scrollRect;
    protected List<object> list = new();
    private RectTransform contentRect;
    private GridLayoutGroup layoutGroup;
    public GameObject item;
    private List<CustomScrollItemMono> scrollTestItems = new();
    private CustomVertial customVertial;
    private int startIndex;
    private int endIndex;
    private int showItemCount = 14;

    private void Awake()
    {
        contentRect = scrollRect.content.GetComponent<RectTransform>();
        layoutGroup = contentRect.GetComponent<GridLayoutGroup>();
        customVertial = contentRect.GetComponent<CustomVertial>();
        scrollRect.horizontal = false;
        scrollRect.vertical = true;
        scrollRect.onValueChanged.AddListener((value) =>
        {
            layoutGroup.enabled = false;
            customVertial.enabled = false;
           
            for (int i = startIndex; i < itemPosList.Count; i++)
            {
                var y = contentRect.anchoredPosition3D.y;
                if (i + layoutGroup.constraintCount < itemPosList.Count) 
                {
                    if (scrollRect.velocity.y > 0)//手指上滑 
                    {
                        var targetY = -itemPosList[i + layoutGroup.constraintCount].y;
                        if (y >= targetY)
                        {
                            startIndex = i + layoutGroup.constraintCount;
                            endIndex = startIndex + showItemCount - layoutGroup.constraintCount;
                            break;
                        }
                    }
                    else if (scrollRect.velocity.y < 0)//手指下滑
                    {
                        if (startIndex > 0 && startIndex  < itemPosDic.Count) 
                        {
                            var targetY = -itemPosDic[startIndex].y;
                            if (y <= targetY)
                            {
                                startIndex = i - layoutGroup.constraintCount;
                                endIndex = startIndex + showItemCount - layoutGroup.constraintCount;
                                break;
                            }
                        }
                    }
                }
            }
            Debug.Log($"bbb startIndex {startIndex} endIndex {endIndex}");
            if (endIndex >= itemPosDic.Count) { return; }
            int index = 0;
            for (int i = startIndex; i < endIndex + layoutGroup.constraintCount; i++)
            {
                if (index < scrollTestItems.Count && i < itemPosDic.Count) 
                {
                    var item = scrollTestItems[index];
                    item.Init(i, list[i]);
                    var rect = item.gameObject.GetComponent<RectTransform>();
                    rect.anchoredPosition3D = itemPosDic[i];
                    index += 1;
                }
            }
        });
    }

    private Dictionary<int, Vector3> itemPosDic = new();
    private List<Vector3> itemPosList = new();

    public void Init() 
    {
        InitListData();
        InitItemsPos();
        InitContentSize();
        InitShowItems();
    }

    public virtual void InitListData() 
    {
        //必须要新建类 继承此类  重写此方法设置数据
    }

    private void InitItemsPos() 
    {
        int prevRow = 0;
        int initIndex = 0;
        for (int i = 0; i < list.Count; i++)
        {
            int row = Mathf.CeilToInt((i + 1) * 1f / layoutGroup.constraintCount);
            var pos = Vector3.zero;
            if (row != prevRow)
            {
                pos = new Vector3(0, -((row - 1) * (layoutGroup.cellSize.y + layoutGroup.spacing.y) + layoutGroup.padding.top));
                initIndex = 0;
            }
            else
            {
                initIndex += 1;
                pos = new Vector3(initIndex * (layoutGroup.cellSize.x + layoutGroup.spacing.x) + layoutGroup.padding.left, -((row - 1) * (layoutGroup.cellSize.y + layoutGroup.spacing.y) + layoutGroup.padding.top));
            }
            itemPosList.Add(pos);
            itemPosDic.Add(i, pos);
            prevRow = row;
        }
    }

    private void InitContentSize() 
    {
        float width = layoutGroup.padding.left + layoutGroup.cellSize.x * layoutGroup.constraintCount +
           (layoutGroup.constraintCount - 1) * layoutGroup.spacing.x;
        float height = layoutGroup.padding.top + layoutGroup.cellSize.y * Mathf.Ceil(itemPosList.Count / layoutGroup.constraintCount) +
            itemPosList.Count / layoutGroup.constraintCount * layoutGroup.spacing.y;
        contentRect.sizeDelta = new Vector2(width, height);
        customVertial.SetSize(new Vector2(width, height));
    }

    private void InitShowItems() 
    {
        for (int i = 0; i < showItemCount; i++)
        {
            GameObject obj = Instantiate(item, contentRect);
            RectTransform rect = obj.GetComponent<RectTransform>();
            rect.anchorMin = new Vector2(0, 1);
            rect.anchorMax = new Vector2(0, 1);
            rect.pivot = new Vector2(0, 1);
            obj.transform.name = i.ToString();
            obj.SetActive(true);
            CustomScrollItemMono testItem = obj.GetComponent<CustomScrollItemMono>();
            testItem.Init(i, list[i]);
            scrollTestItems.Add(testItem);
        }
        item.SetActive(false);
    }
}

public class ScrollTestData 
{
    public int ID;
}

using System.Collections.Generic;
using UnityEngine;

public interface ICustomScrollItem
{
    public void Init(int index,object data);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

//这个类一定要挂在GridLayout下面 控制Content尺寸
public class CustomVertial : ContentSizeFitter
{
    private Vector2 size = new();
    private RectTransform rectTransform;

    protected override void Awake()
    {
        base.Awake();
        rectTransform = GetComponent<RectTransform>();
    }

    public void SetSize(Vector2 s) 
    {
        size = s;
    }

    public override void SetLayoutVertical()
    {
        base.SetLayoutVertical();
        rectTransform.sizeDelta = size;
    }
}
using System.Collections.Generic;
using UnityEngine;

public class CustomScrollItemMono : MonoBehaviour,ICustomScrollItem
{
    public void Init(int index, object data)
    {
        InitView(index, data);
    }

    public virtual void InitView(int index, object data) 
    {

    }
}

二 具体使用实例类

1.挂在ScrollRect组件下面 在面板上设置好Scroll和Content和子元素Item

   重写了InitListData 方法 设置需要的列表数据  这里测试放在Start里面启动列表

   实际根据具体逻辑启动

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

public class CustomScrollTest:CustomScroll
{
    public override void InitListData()
    {
        base.InitListData();
        for (int i = 0; i < 100; i++)
        {
            list.Add(new ScrollTestData() { ID = i });
        }
    }

    private void Start()
    {
        Init();
    }
}

2.具体的Item元素类 挂在Item上

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

public class ScrollTestItem : CustomScrollItemMono
{
    public Text text;
    private ScrollTestData Data= new();
    private int Index;

    public override void InitView(int index, object data)
    {
        ScrollTestData testData = (ScrollTestData)data;
        Index = index;
        Data = testData;
        text.text = Index.ToString();
        transform.name = Index.ToString();
    }
}


http://www.kler.cn/a/416280.html

相关文章:

  • GPU 服务器厂家:怎样铸就卓越 AI 算力?
  • DETR:一种新颖的端到端目标检测与分割框架
  • mac访达打开终端
  • github webhooks 实现网站自动更新
  • AI加持,华为全屋智能品牌升级为“鸿蒙智家”
  • 探索Java 17的新特性
  • 算法——赎金信(leetcode383)
  • android user版本默认usb模式为充电模式
  • C++趣味编程:基于树莓派Pico的模拟沙漏-倾斜开关与LED的互动实现
  • 深入理解 AI 产品的核心价值——《AI产品经理手册》
  • golang通用后台管理系统11(代码生成工具01)
  • 40分钟学 Go 语言高并发:【实战课程】工作池(Worker Pool)实现
  • hhdb数据库介绍(10-13)
  • 【Python-Open3D学习笔记】004Mesh生成方法
  • windows安全中心,永久卸载工具分享
  • (超详细图文)PLSQL Developer 配置连接远程 Oracle 服务
  • 前端安全防护教程
  • 05—如何设计和仿真阻抗匹配网络
  • MySQL之创建和管理表
  • postman使用正则表达式提取数据实战篇!