Unity-UGUI无限循环列表

2019-07-26 14:58:41 浏览数 (3)

Unity版本:2017.4

简介: UGUI使用ScrollView、GridLayoutGroup实现无限循环列表,支持数据刷新,支持跳转,支持动态插入/删除

使用说明: 点击UI中的ID进行删除,键盘按下A添加ID。 在Inspector面板中输入MaxItemCount 列表最大数量。TargetID输入要跳转的ID,键盘按下Space跳转到要查找的ID。

代码语言:javascript复制
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CSInfiniteScrolling : MonoBehaviour
{

    public int maxItemCount = 0;
    public int targetID = 0;

    private int rowCount = 0;
    private int columnCount = 0;
    private int curTopIndex = 0;
    private int initializedBottomIndex = 0;
    private int curBottomIndex = 0;
    private int contentCurTopPosY = 0;
    private int oneBlockHeight = 0;
    private int curIndex = 0;

    private List<int> itemIDs;

    private ScrollRect scrollRect;
    private RectTransform content;
    private GridLayoutGroup contentGridLayoutGroup;

    private void Awake()
    {
        scrollRect = GetComponent<ScrollRect>();

        content = scrollRect.content;
        contentGridLayoutGroup = content.GetComponent<GridLayoutGroup>();


        columnCount = (int)(content.rect.width - contentGridLayoutGroup.spacing.x) / (int)contentGridLayoutGroup.cellSize.x;
        if (columnCount != 0)
        {
            rowCount = (int)Mathf.Ceil(content.transform.childCount / columnCount);
            curBottomIndex = (rowCount - 1) * columnCount;
            initializedBottomIndex = curBottomIndex;
        }

        oneBlockHeight = (int)(contentGridLayoutGroup.cellSize.y   contentGridLayoutGroup.spacing.y);
        content.sizeDelta = new Vector2(content.sizeDelta.x, (int)Mathf.Ceil((float)maxItemCount / (float)columnCount) * oneBlockHeight);//向上取整

        itemIDs = new List<int>();
        for (int i = 0; i < maxItemCount; i  )
        {
            itemIDs.Add(i);
        }

    }

    // Use this for initialization
    void Start()
    {
        scrollRect = GetComponent<ScrollRect>();
        scrollRect.onValueChanged.AddListener(ListenerMethod);
        FreshBackpack();
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            JumpToTargetID(targetID);
        }
        if (Input.GetKeyDown(KeyCode.A))
        {
            AddRandomID();
            FreshBackpack();
        }
    }

    private void AddRandomID()
    {
        if (itemIDs.Count<maxItemCount)
        {
            System.Random random = new System.Random();
            itemIDs.Add(random.Next(0, 100));
        }
        else
        {
            Debug.Log("Backpack is Full!");
        }
    }

    private void InitializedChildButton(Transform transformChild,int index = -1)
    {
        if (index != -1)
        {
            Button.ButtonClickedEvent buttonClickedEvent = new Button.ButtonClickedEvent();
            buttonClickedEvent.AddListener(() => {
                itemIDs.RemoveAt(index);
                FreshBackpack();
            });
            transformChild.GetComponent<Button>().onClick = buttonClickedEvent;
        }
        else
        {
            Button.ButtonClickedEvent buttonClickedEvent = new Button.ButtonClickedEvent();
            buttonClickedEvent.AddListener(() => {
                Debug.Log("None Object");
            });
            transformChild.GetComponent<Button>().onClick = buttonClickedEvent;
        }
    }

    private void ListenerMethod(Vector2 contentPos)
    {
        if ((content.localPosition.y - contentCurTopPosY) > oneBlockHeight)
        {
            while ((content.localPosition.y - contentCurTopPosY) > oneBlockHeight)
            {
                contentCurTopPosY = contentCurTopPosY   oneBlockHeight;
                for (int i = 0; i < columnCount; i  )
                {
                    RectTransform rectTransform = content.transform.GetChild(curTopIndex   i).GetComponent<RectTransform>();
                    rectTransform.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, rectTransform.anchoredPosition.y - oneBlockHeight * rowCount);
                }

                curTopIndex  = columnCount;
                curBottomIndex  = columnCount;
                curTopIndex = curTopIndex % content.childCount;
                curBottomIndex = curBottomIndex % content.childCount;
                curIndex  = columnCount;
            }
            FreshBackpack();
        }
        else if ((content.localPosition.y - contentCurTopPosY) < -contentGridLayoutGroup.spacing.y)
        {
            while ((content.localPosition.y - contentCurTopPosY) < -contentGridLayoutGroup.spacing.y)
            {
                contentCurTopPosY = contentCurTopPosY - oneBlockHeight;
                for (int i = 0; i < columnCount; i  )
                {
                    RectTransform rectTransform = content.transform.GetChild(curBottomIndex   i).GetComponent<RectTransform>();
                    rectTransform.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, rectTransform.anchoredPosition.y   oneBlockHeight * rowCount);
                }

                curTopIndex = (curTopIndex   content.childCount) - columnCount;
                curBottomIndex = (curBottomIndex   content.childCount) - columnCount;
                curTopIndex = curTopIndex % content.childCount;
                curBottomIndex = curBottomIndex % content.childCount;
                curIndex -= columnCount;
            }
            FreshBackpack();
        }
    }
    private void FreshBackpack()
    {
        int offset = 0;
        for (int i = 0; i < content.childCount; i  )
        {
            Transform textChild = content.GetChild((curTopIndex   i) % content.childCount).GetChild(0);
            if ((curIndex   offset) < itemIDs.Count)
            {
                textChild.GetComponent<Text>().text = ""   itemIDs[curIndex   offset];
                InitializedChildButton(content.GetChild((curTopIndex   i) % content.childCount), curIndex   offset);
                offset  ;
            }
            else
            {
                textChild.GetComponent<Text>().text = "";
                InitializedChildButton(content.GetChild((curTopIndex   i) % content.childCount));
                offset  ;
            }
        }
    }

    public void JumpToTargetID(int ID)
    {
        int index = -1;
        for (int i = 0; i < itemIDs.Count; i  )
        {
            if (ID == itemIDs[i])
            {
                index = i;
                break;
            }
        }

        if (index == -1)
            return;

        curIndex = index - (index % columnCount);
        curTopIndex = 0;
        curBottomIndex = initializedBottomIndex;
        float newContentLocalPosY = ((curIndex   1) / columnCount) * oneBlockHeight;
        content.localPosition = new Vector2(content.localPosition.x, ((curIndex   1) / columnCount) * oneBlockHeight);
        contentCurTopPosY = (int)content.localPosition.y;

        int curTopRowIndex = curIndex / columnCount;
        for (int i = 0; i < content.childCount; i  )
        {
            RectTransform rectTransform = content.GetChild(i).GetComponent<RectTransform>();
            int newAnchoredPosY = (curTopRowIndex * -oneBlockHeight)   (-oneBlockHeight * (i / columnCount) - (int)(0.5 * content.GetComponent<GridLayoutGroup>().cellSize.y));
            rectTransform.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, newAnchoredPosY);
        }
        FreshBackpack();
    }
}

物品没有直接挂载Button,通过代码控制Button的挂载

代码语言:javascript复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PressToDelID : MonoBehaviour {
    private Button button;
    private void Awake()
    {
        button = gameObject.GetComponent<Button>();

        if (button == null)
        {
            gameObject.AddComponent<Button>();
        }
    }
}

用Lua实现

代码语言:javascript复制
import "UnityEngine"
import "UnityEngine.UI"

local breakSocketHandle,debugXpCall = require("LuaDebugjit")("localhost",7003)
LuaTimer.Add(0,1000,function(id)
    breakSocketHandle()
end)

local scrollRect;
local content;
local contentGridLayoutGroup;
local columnCount;
local rowCount;
local initializedBottomIndex;
local oneBlockHeight;
local maxItemCount = 0;
local itemIDs = {};
local scrollRect;

local contentCurTopPosY = 0;
local curTopIndex = 0;
local curBottomIndex = 0;
local curIndex = 1;

local class = {}

function main()
    maxItemCount = 40;

    scrollRect = GameObject.Find("Canvas/Backpack"):GetComponent(UI.ScrollRect);
    
    content = scrollRect.content;
    contentGridLayoutGroup = content:GetComponent(UI.GridLayoutGroup);

    columnCount = math.floor((content.rect.width - contentGridLayoutGroup.spacing.x)/contentGridLayoutGroup.cellSize.x);
    if columnCount ~= 0 then
        rowCount = math.ceil( content.childCount/columnCount );
        curBottomIndex = (rowCount - 1)*columnCount;
        initializedBottomIndex = curBottomIndex;
    end

    oneBlockHeight = contentGridLayoutGroup.cellSize.y   contentGridLayoutGroup.spacing.y;
    local contentSizeDeltaY = math.floor( oneBlockHeight * (math.ceil(maxItemCount / columnCount))) ;
    content.sizeDelta = UnityEngine.Vector2(content.sizeDelta.x,contentSizeDeltaY);

    for i=1,maxItemCount do
        table.insert(itemIDs,i);
    end

    scrollRect.onValueChanged:AddListener(ListenerMethod);
    FreshBackpack();

    return class;
end

function class : Update()
    if UnityEngine.Input.GetKeyDown(KeyCode.Space) then
        JumpToTargetID(12);
    end
    if UnityEngine.Input.GetKeyDown(KeyCode.A) then
        if #itemIDs < maxItemCount then
            table.insert( itemIDs,math.random(0,100) );
            FreshBackpack();
        else
            print("BP Full!");
        end
    end
end

function ListenerMethod()
    if ((content.localPosition.y - contentCurTopPosY) > oneBlockHeight) then
        while ((content.localPosition.y - contentCurTopPosY) > oneBlockHeight)
            do
                contentCurTopPosY = contentCurTopPosY   oneBlockHeight;
                for i=1,columnCount do
                    local child = content.transform:GetChild(curTopIndex   i - 1);
                    local rectTransform = child:GetComponent(UnityEngine.RectTransform);
                    rectTransform.anchoredPosition = UnityEngine.Vector2(rectTransform.anchoredPosition.x, rectTransform.anchoredPosition.y - oneBlockHeight * rowCount);
                end
                curTopIndex = curTopIndex   columnCount;
                curBottomIndex =    curBottomIndex  columnCount;
                curTopIndex = curTopIndex % content.childCount;
                curBottomIndex = curBottomIndex % content.childCount;
                curIndex =curIndex  columnCount;
            end
            FreshBackpack();
    elseif ((content.localPosition.y - contentCurTopPosY) < -contentGridLayoutGroup.spacing.y) then
        while ((content.localPosition.y - contentCurTopPosY) < -contentGridLayoutGroup.spacing.y) do
                contentCurTopPosY = contentCurTopPosY - oneBlockHeight;
                for i=1,columnCount do
                    local rectTransform = content.transform:GetChild(curBottomIndex   i -1):GetComponent(UnityEngine.RectTransform);
                    rectTransform.anchoredPosition = UnityEngine.Vector2(rectTransform.anchoredPosition.x, rectTransform.anchoredPosition.y   oneBlockHeight * rowCount);
                end
                curTopIndex = (curTopIndex   content.childCount) - columnCount;
                curBottomIndex = (curBottomIndex   content.childCount) - columnCount;
                curTopIndex = curTopIndex % content.childCount;
                curBottomIndex = curBottomIndex % content.childCount;
                curIndex =curIndex - columnCount;
        end
            FreshBackpack();
    end
end

function FreshBackpack()
    local offset = 0;
    for i=1,content.childCount do
        local contentChild = content:GetChild((curTopIndex   i - 1) % content.childCount);
        local textChild = contentChild:GetChild(0);
        if ((curIndex   offset) <= #itemIDs) then
            textChild:GetComponent(UI.Text).text = tostring(itemIDs[curIndex   offset]) ;
            InitializedChildButton(contentChild, curIndex   offset);
        else
            textChild:GetComponent(UI.Text).text = "";
            InitializedChildButton(contentChild);
        end
        offset = offset   1;
    end
end

function InitializedChildButton(contentChild,index)
    local buttonClickedEvent = Button:ButtonClickedEvent();
            buttonClickedEvent:AddListener(function()
                if (index ~= nil) then
                    table.remove( itemIDs,index );
                    FreshBackpack();
                else
                    print("None Object");
                end
            end);
    contentChild:GetComponent(UI.Button).onClick = buttonClickedEvent;
end

function JumpToTargetID( ID )
    local index;
    for i=1,#itemIDs do
        if ID == itemIDs[i] then
            index = i;
            break;
        end
    end
    if index == nil then
        return nil;
    end

    curIndex = index - (index - 1 ) % columnCount;
    curTopIndex = 0;
    curBottomIndex = initializedBottomIndex;
    local newContentLocalPosY = math.floor( curIndex  / columnCount ) * oneBlockHeight;
    content.localPosition = UnityEngine.Vector2(content.localPosition.x,newContentLocalPosY);
    contentCurTopPosY =content.localPosition.y;

    local curTopRowIndex = (curIndex-1) / columnCount;
    for i=1,content.childCount do
        local rectTransform = content:GetChild(i-1):GetComponent(UnityEngine.RectTransform);
        local newAnchoredPosY = (curTopRowIndex * -oneBlockHeight)   (-oneBlockHeight * math.floor((i-1) / columnCount) - math.floor(0.5 * content:GetComponent(UI.GridLayoutGroup).cellSize.y));
        rectTransform.anchoredPosition = UnityEngine.Vector2(rectTransform.anchoredPosition.x,newAnchoredPosY);
    end

    FreshBackpack();
end

0 人点赞