当前位置:网站首页>Application example of infinite list [uigridview]

Application example of infinite list [uigridview]

2022-07-07 15:52:00 Le_ Sam

 UIGridView Source code

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

//Introduction:  Infinite list 
//Content Mount forbidden on ContentSizeFilter and LayOutGroup And so on 
[DisallowMultipleComponent]
[RequireComponent(typeof(ScrollRect))]
public class UIGridView : MonoBehaviour
{
    private Action<Transform, int> _handle;

    public enum Arrangement
    {
        Horizontal = 0,
        Vertical,
    }

    public enum HorizontalAlign
    {
        Left,
        Middle,
        Right,
    }

    public enum VerticalAlign
    {
        Top,
        Middle,
        Bottom,
    }
    public Arrangement arrangement = Arrangement.Vertical;

    //  It is useful when choosing horizontal or vertical flow , Refers to each line / Maximum number of columns 
    public int MaxPerLine
    {
        get { return maxPerLine; }
        set { SetMaxPerLine(value); }
    }

    public HorizontalAlign horizontalAlign = HorizontalAlign.Left;
    public VerticalAlign verticalAlign = VerticalAlign.Top;
    public Vector2 viewPort;

    public float rowSpace = 0;
    public float columuSpace = 0;
    public float marginTop = 0;
    public float marginBottom = 0;
    public float marginLeft = 0;
    public float marginRight = 0;

    public int maxPerLine;
    public int childCount; // The total number of data to be rendered 
    public GameObject item;
    

    public GameObject Child
    {
        get { return item; }
        set { SetItem(value); }
    }

    public int ChildCount
    {
        get { return childCount; }
        set { SetChildCount(value, true); }
    }

    public Vector2 ViewPort
    {
        get { return viewPort; }
        set { SetViewPort(value); }
    }

    
    ScrollRect scrollRect;
       
    RectTransform content;
    Vector2 itemSize;
    List<Transform> items;
    Dictionary<int, int> contains;
    List<int> outOfContains;
    
    int scrollLineIndex; // Current first element index 
    int totalCount; // stay UI The number shown in ( Not multiplied by maxPerLine)
    Vector2 startPos; // Where the first element is located 
    int startIndex; // Current rendering start coordinates 
    int endIndex; // Current rendering end coordinates 
        

    void Start()
    {
        maxPerLine = maxPerLine == 0 ? 1 : maxPerLine;
        items = new List<Transform>();
        contains = new Dictionary<int, int>();
        outOfContains = new List<int>();
        scrollRect = transform.GetComponent<ScrollRect>();
        content = scrollRect.content;
        if (content == null)
        {
            Debug.Log("ScrollRect " + scrollRect.gameObject.name + " Has No Content, Please Check And Retry.");
            return;
        }
        //viewPort = scrollRect.viewport.rect.size;

        if (item != null)
            SetItem(item);

        content.anchorMax = new Vector2(0, 1);
        content.anchorMin = new Vector2(0, 1);
        content.pivot = new Vector2(0, 1);
        ReBuild();
    }

    public void ReBuild()
    {
        if (scrollRect == null || content == null || item == null) return;
        ResetChildren();

        Vector2 maskSize = viewPort;
        int count = 0;

        if (arrangement == Arrangement.Horizontal)
        {
            count = Mathf.CeilToInt(maskSize.x / itemSize.x) + 1; // Number of horizontal columns 
            startPos = Vector2.zero;
            startPos.x = marginLeft;
            if (verticalAlign == VerticalAlign.Top)
            {
                startPos.y = -marginTop;
            }
            else if (verticalAlign == VerticalAlign.Middle)
            {
                startPos.y = -(maskSize.y * 0.5f - (itemSize.y * maxPerLine + (maxPerLine - 1) * rowSpace) * 0.5f);
            }
            else if (verticalAlign == VerticalAlign.Bottom)
            {
                startPos.y = -(maskSize.y - marginBottom - itemSize.y * maxPerLine - rowSpace * (maxPerLine - 1));
            }
        }
        else if (arrangement == Arrangement.Vertical)
        {
            count = Mathf.CeilToInt(maskSize.y / itemSize.y) + 1; // Number of vertical rows 
            startPos = Vector2.zero;
            startPos.y = -marginTop; // Reset the start node position 
            if (horizontalAlign == HorizontalAlign.Left)
            {
                startPos.x = marginLeft;
            }
            else if (horizontalAlign == HorizontalAlign.Middle)
            {
                startPos.x = (maskSize.x * 0.5f - (itemSize.x * maxPerLine + (maxPerLine - 1) * columuSpace) * 0.5f);
            }
            else if (horizontalAlign == HorizontalAlign.Right)
            {
                startPos.x = maskSize.x - marginRight - itemSize.x * maxPerLine - columuSpace * (maxPerLine - 1);
            }
        }
        totalCount = count;

        SetChildCount(childCount, true);
        BackTop();

        scrollRect.onValueChanged.RemoveAllListeners();
        scrollRect.onValueChanged.AddListener(OnValueChanged);
    }


    // List scrolling 
    private void OnValueChanged(Vector2 vec)
    {
        switch (arrangement)
        {
            case Arrangement.Horizontal:
                vec.x = Mathf.Clamp(vec.x, 0, 1);
                break;
            case Arrangement.Vertical:
                vec.y = Mathf.Clamp(vec.y, 0, 1);
                break;
        }

        int curLineIndex = GetCurLineIndex();
        if (curLineIndex != scrollLineIndex)
            UpdateRectItem(curLineIndex, false);
    }

    private int GetCurLineIndex()
    {
        switch (arrangement)
        {
            case Arrangement.Horizontal:
                return
                    Mathf.FloorToInt(Mathf.Abs(content.anchoredPosition.x < 0.1f ? content.anchoredPosition.x : 0.1f - marginLeft) /
                                        (columuSpace + itemSize.x));
            case Arrangement.Vertical:
                return
                    Mathf.FloorToInt(Mathf.Abs(content.anchoredPosition.y > -0.1f ? content.anchoredPosition.y : -0.1f - marginTop) /
                                        (rowSpace + itemSize.y));
        }
        return 0;
    }

    private void UpdateRectItem(int curLineIndex, bool forceRender)
    {
        if (curLineIndex < 0)
            return;
        startIndex = curLineIndex * maxPerLine;
        endIndex = (curLineIndex + totalCount) * maxPerLine;
        if (endIndex >= childCount)
            endIndex = childCount;

        contains.Clear(); // Render sequence number 
        outOfContains.Clear(); //items The index of 
        for (int i = 0; i < items.Count; i++)// If currently rendered item Contained in the 
        {
            int index = int.Parse(items[i].gameObject.name);
            if (index < startIndex || index >= endIndex)
            {
                outOfContains.Add(i);
                items[i].gameObject.SetActive(false);
            }
            else
            {
                items[i].gameObject.SetActive(true);
                contains.Add(index, i);
            }
        }

        // ************* Change rendering ****************
        for (int i = startIndex; i < endIndex; i++)
        {
            if (!contains.ContainsKey(i))
            {
                Transform child = items[outOfContains[0]];
                outOfContains.RemoveAt(0);
                child.gameObject.SetActive(true);
                int row = i / maxPerLine;
                int col = i % maxPerLine;
                if (arrangement == Arrangement.Vertical)
                    child.localPosition = startPos +
                                            new Vector2(col * itemSize.x + (col) * columuSpace,
                                                -row * itemSize.y - (row) * rowSpace);
                else
                    child.localPosition = startPos +
                                            new Vector2(row * itemSize.x + (row) * columuSpace,
                                                -col * itemSize.y - (col) * rowSpace);
                child.gameObject.name = i.ToString();
                if (_handle != null)
                    _handle(child, i);
            }
            else if (forceRender)
            {
                if (_handle != null)
                    _handle(items[contains[i]], i);
            }
        }

        scrollLineIndex = curLineIndex;
    }

    ///  Remove all current 
    private void ResetChildren()
    {
        items.Clear();
        for (int i = 0; i < content.childCount; i++)
        {
            Transform child = content.GetChild(i);
            child.gameObject.SetActive(false);
        }
    }
    
    //  Create a new node 
    private RectTransform CreateItem(int index)
    {
        Transform child;
        if (content.childCount > index)
        {
            child = content.GetChild(index);
        }
        else
        {
            GameObject obj = GameObject.Instantiate(item) as GameObject;
            obj.transform.SetParent(content);
            obj.transform.localScale = Vector3.one;
            child = obj.transform;
        }
        child.gameObject.name = index.ToString();
        items.Add(child);

        return child as RectTransform;
    }

    //  Set up resources 
    public void SetItem(GameObject child)
    {
        if (child == null) return;
        this.item = child;
        RectTransform itemTrans = child.transform as RectTransform;
        itemTrans.pivot = new Vector2(0, 1);
        itemSize = itemTrans.sizeDelta;
        //ReBuild();
    }

    //  Update the number of renderings needed 
    public void SetChildCount(int value, bool forceRender)
    {
        if (value < 0) childCount = 0;
        else childCount = value;

        if (totalCount <= 0)// Not initialized yet 
            return;
        if (value > items.Count && items.Count < maxPerLine * totalCount)
        {
            // The current number of grids is less than the number that should be generated 
            int count = items.Count;
            int max = value < maxPerLine * totalCount ? value : maxPerLine * totalCount;
            for (int i = count; i < max; i++)
            {
                int row = i / maxPerLine;
                int col = i % maxPerLine;
                RectTransform child = CreateItem(i);
                if (arrangement == Arrangement.Vertical)
                    child.localPosition = startPos +
                                            new Vector2(col * itemSize.x + (col) * columuSpace,
                                                -row * itemSize.y - (row) * rowSpace);
                else
                    child.localPosition = startPos +
                                            new Vector2(row * itemSize.x + (row) * columuSpace,
                                                -col * itemSize.y - (col) * rowSpace);
            }
        }

        if (content == null) return;

        int rc = Mathf.CeilToInt((float)childCount / (float)maxPerLine); // Set up content Size 
        if (arrangement == Arrangement.Horizontal)
        {
            content.sizeDelta = new Vector2(marginLeft + marginRight + itemSize.x * rc + columuSpace * (rc - 1),
                viewPort.y);
            if (content.sizeDelta.x > viewPort.x && content.anchoredPosition.x < viewPort.x - content.sizeDelta.x)
                content.anchoredPosition = new Vector2(viewPort.x - content.sizeDelta.x, content.anchoredPosition.y);
        }
        else
        {
            content.sizeDelta = new Vector2(viewPort.x, marginTop + marginBottom + itemSize.y * rc + rowSpace * (rc - 1));
            if (content.sizeDelta.y > viewPort.y && content.anchoredPosition.y > content.sizeDelta.y - viewPort.y)
                content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.sizeDelta.y - viewPort.y);
        }
        UpdateRectItem(GetCurLineIndex(), true);
    }

    //  Add child nodes 
    public void AddChild(int index)
    {
        if (index < 0) return;
        startIndex = scrollLineIndex * maxPerLine;
        endIndex = (scrollLineIndex + totalCount) * maxPerLine;
        SetChildCount(childCount + 1, index >= startIndex && index < endIndex);
    }

    //  Delete child nodes 
    public void RemoveChild(int index)
    {
        if (index < 0 || index >= childCount) return;
        startIndex = scrollLineIndex * maxPerLine;
        endIndex = (scrollLineIndex + totalCount) * maxPerLine;
        SetChildCount(childCount - 1, index >= startIndex && index < endIndex);
    }


    // <summary>
    //  Set the display window size ( It seems that it can be abandoned now )
    public void SetViewPort(Vector2 port)
    {
        if (port == viewPort) return;
        viewPort = port;
        //ReBuild();
    }

    //  Set the row and column maximum 
    public void SetMaxPerLine(int max)
    {
        maxPerLine = max;
        //ReBuild();
    }
    
    //  Return to the top 
    public void BackTop()
    {
        content.localPosition = Vector3.zero;
        UpdateRectItem(0, true);
    }


    //  Go back to the bottom 
    public void BackBottom()
    {
        if (arrangement == Arrangement.Vertical)
        {
            content.localPosition = new Vector3(0, -viewPort.y + content.sizeDelta.y, 0);
        }
        else
        {
            content.localPosition = new Vector3(viewPort.x - content.sizeDelta.x, 0);
        }
        UpdateRectItem(Mathf.CeilToInt((float)childCount / (float)maxPerLine) - totalCount + 1, true);
    }

    public void RefreshViewItem()
    {
        UpdateRectItem(scrollLineIndex, true);
    }


    public void SetArrangement(int arr)
    {
        arrangement = (Arrangement)arr;
    }

    public void SetHorizontal(int h)
    {
        horizontalAlign = (HorizontalAlign)h;
    }

    public void SetVerticle(int v)
    {
        verticalAlign = (VerticalAlign)v;
    }

    public void AddChangeItemListener(Action<Transform, int> handle)
    {
        _handle = handle;
    }
}

  Example :
Lua Application example :

local Tool = require("Tool")
 
local SprogExtendWindow = {}

local mediate = nil
local gridView = nil
local extendItem = nil
local extendItemInfo = nil
local sortList = nil
local extendCfgs = nil

local rewardState = 
{
    UNFINISH = 0,  -- Can claim 
    UNREACH  = 1,  -- Not achieved 
    FINISHED = 2,  -- Have received 
}

function SprogExtendWindow.Init(data)

	mediate = data

    --  establish ITEM example 
    ResMgr.LoadAssets("prefab", { "SprogExtendItem" },function(objs)
        extendItem = objs[0]
    end)

	extendItemInfo = {} --  The server sends data 
    sortList = {} --  The front end has been sorted , Data for display 

    SprogExtendWindow.InitGridView()
    SprogExtendWindow.RegistEvents()

    SprogExtendWindow.UpdateAllExtendInfo()
	return SprogExtendWindow
end

function SprogExtendWindow.InitGridView()

    gridView = mediate:FindChild("Layer_Sprite/panelGroup/extendPanel/bottom/Scroll View"):GetComponent("UIGridView") --  obtain UIGridView Components 
    gridView.maxPerLine = 1
    gridView.rowSpace = 1
    gridView:SetItem(extendItem)
    gridView:SetViewPort(Vector2(565,325))

    --  stay ScrollView OnSwipe ,UIGridView Will recall the upcoming item, The client only needs to fill in the corresponding UI data .
    -- PS:  This function will keep calling , We have to consider performance , Avoid dealing with too large data 
    gridView:AddChangeItemListener(function(transform, index)
        local index = index + 1

        if sortList and sortList[index] then
            local item = sortList[index]
            Tool.subGetObject(transform, "time", "Text").text = item.config.time .. " " .. item.config.id
            Tool.subGetObject(transform, "content", "Text").text = item.config.name
            Tool.subGetObject(transform, "image", "Image").sprite = Tool.LoadImgSpriteFromAb("image", item.config.img)

            SprogExtendWindow.SetStateInfo(item.state, transform)

            transform:FindChild("Button").onClick = function(obj, eventData)
                SprogExtendWindow.CheckExtendItemInfo(item.config.id, transform)
            end
        end
	end)

end


function SprogExtendWindow.RegistEvents()

	mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_num", function () 
		log(" Button 1")
	end)

	mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_link", function () 
		log(" Button 2")
    end)
        
	mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_share", function () 
		log(" Button 3")
	end)
end

function SprogExtendWindow.InitScrollView()

end

function SprogExtendWindow.UpdateAllExtendInfo()

    -- TEST, Select temporary data 
    local data = 
    {
        [1] = {id = 1, type = 1, time = "2020.01.01", name = " The bed ", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},
        [2] = {id = 2, type = 1, time = "2020.01.02", name = " front ", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},
        [3] = {id = 3, type = 1, time = "2020.01.03", name = " bright ", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},
        [4] = {id = 4, type = 1, time = "2020.01.04", name = " month ", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},
        [5] = {id = 5, type = 1, time = "2020.01.05", name = " light ", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999},
        [6] = {id = 6, type = 1, time = "2020.01.06", name = " The bed ", img = "yxdt_tx1.png", vip = 6, liquanNum = 99999},
        [7] = {id = 7, type = 1, time = "2020.01.07", name = " front ", img = "yxdt_tx1.png", vip = 7, liquanNum = 99999},   
        [8] = {id = 8, type = 1, time = "2020.01.08", name = " bright ", img = "yxdt_tx1.png", vip = 8, liquanNum = 99999},
        [9] = {id = 9, type = 1, time = "2020.01.09", name = " month ", img = "yxdt_tx1.png", vip = 9, liquanNum = 99999},
        [10] = {id = 10, type = 1, time = "2020.01.10", name = " light ", img = "yxdt_tx1.png", vip = 10, liquanNum = 99999},
        [11] = {id = 11, type = 1, time = "2020.01.01", name = " The bed ", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},
        [12] = {id = 12, type = 1, time = "2020.01.02", name = " front ", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},
        [13] = {id = 13, type = 1, time = "2020.01.03", name = " bright ", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},
        [14] = {id = 14, type = 1, time = "2020.01.04", name = " month ", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},
        [15] = {id = 15, type = 1, time = "2020.01.05", name = " light ", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999},
        [16] = {id = 16, type = 1, time = "2020.01.06", name = " The bed ", img = "yxdt_tx1.png", vip = 6, liquanNum = 99999},
        [17] = {id = 17, type = 1, time = "2020.01.07", name = " front ", img = "yxdt_tx1.png", vip = 7, liquanNum = 99999},   
        [18] = {id = 18, type = 1, time = "2020.01.08", name = " bright ", img = "yxdt_tx1.png", vip = 8, liquanNum = 99999},
        [19] = {id = 19, type = 1, time = "2020.01.09", name = " month ", img = "yxdt_tx1.png", vip = 9, liquanNum = 99999},
        [20] = {id = 20, type = 1, time = "2020.01.10", name = " light ", img = "yxdt_tx1.png", vip = 10, liquanNum = 99999},
        [21] = {id = 21, type = 1, time = "2020.01.01", name = " The bed ", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},
        [22] = {id = 22, type = 1, time = "2020.01.02", name = " front ", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},
        [23] = {id = 23, type = 1, time = "2020.01.03", name = " bright ", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},
        [24] = {id = 24, type = 1, time = "2020.01.04", name = " month ", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},
        [25] = {id = 25, type = 1, time = "2020.01.05", name = " light ", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999}
    } 

    extendItemInfo = {}
    for k, v in ipairs(data) do
        extendItemInfo[v.id] = 
        {   
            config = v, --  Local configuration 
            state = math.random(0, 2) --  A random state 
        }
    end

    SprogExtendWindow.OnSortAllExtendItem()

    gridView.ChildCount = #sortList --  Set up current item total 
    gridView:ReBuild() --  start-up UIGridView
end

--  Sort the data and sort 
function SprogExtendWindow.OnSortAllExtendItem()

    --  Press rewardState grouping ,  Can claim > Not achieved > Have received 
    local templist = {}
    for index = 1, 3 do
        for _,v in ipairs(extendItemInfo) do
            if index == v.state + 1 then
                if templist[index] == nil then
                    templist[index] = {}
                end
                table.insert(templist[index], v)
            end
        end
    end

    --  Each group by VIP Rank order 
    for _,v in ipairs(templist) do
        table.sort(v, function (a, b)
			return a.config.vip > b.config.vip
		end)
	end

    sortList = {}
    for _,v in ipairs(templist) do
        for _,m in ipairs(v) do
            table.insert(sortList, m)
        end
	end

    -- log(" List after sorting  " .. tostring(sortList))
end

function SprogExtendWindow.SetStateInfo(state, obj)
    local text = nil
    local isInteract = nil
    if state == rewardState.UNREACH then
        text = " Not achieved "
        isInteract = false
    elseif state == rewardState.UNFINISH then
        text =  " Can claim "
        isInteract = true
    elseif state == rewardState.FINISHED then
        text =  " Have received "
        isInteract = false
    end

    obj.transform:FindChild("Button").interactable = isInteract
    Tool.subGetObject(obj, "Button/Text", "Text").text = text
end

function SprogExtendWindow.CheckExtendItemInfo(id, obj)

    if extendItemInfo ~= nil and extendItemInfo[id] ~= nil then

        local item = extendItemInfo[id]

        local reqSuccess = function(www)
            --local data = Json.decode(www.text).data
            log(" Claim success ,data: " .. CC.uu.Dump(data))
            
            item.state = 2
            SprogExtendWindow.SetStateInfo(item.state, obj)
        end
        
        local reqFailed = function(err)
            log(" Failed to collect :" .. tostring(err))
        end
    
        --  Send a request 
        local Url = Tool.UrlMgr.UrlMapping("http://172.0.0.1:8000/GetTestData", {id = id, channelId = id})
        Tool.HttpPost(Url, nil, reqSuccess, reqSuccess)
    end
end


function SprogExtendWindow.Destroy()


end

return SprogExtendWindow

 

Unity Component mount :








 

原网站

版权声明
本文为[Le_ Sam]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202130609270803.html