当前位置:网站首页>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 :
边栏推荐
- Cut ffmpeg as needed, and use emscripten to compile and run
- Do not use memset to clear floating-point numbers
- 2022 all open source enterprise card issuing network repair short website and other bugs_ 2022 enterprise level multi merchant card issuing platform source code
- [quick start of Digital IC Verification] 29. Ahb-sramc (9) (ahb-sramc svtb overview) of SystemVerilog project practice
- 过度依赖补助,大客户收款难,冲刺“国产数据库第一股”的达梦后劲有多足?
- 尤雨溪,来了!
- Getting started with webgl (4)
- Use moviepy Editor clips videos and intercepts video clips in batches
- Ida Pro reverse tool finds the IP and port of the socket server
- Three. JS introductory learning notes 00: coordinate system, camera (temporarily understood)
猜你喜欢
[quick start of Digital IC Verification] 18. Basic grammar of SystemVerilog learning 5 (concurrent threads... Including practical exercises)
What is Base64?
Yunxiaoduo software internal test distribution test platform description document
How to create Apple Developer personal account P8 certificate
Zhongang Mining: Fluorite continues to lead the growth of new energy market
过度依赖补助,大客户收款难,冲刺“国产数据库第一股”的达梦后劲有多足?
C4D learning notes 1- animation - animation key frames
Apache Doris刚“毕业”:为什么应关注这种SQL数据仓库?
Virtual memory, physical memory /ram what
Tkinter after how to refresh data and cancel refreshing
随机推荐
Syntaxhighlight highlights the right scroll bar
Postman generate timestamp, future timestamp
[quick start of Digital IC Verification] 18. Basic grammar of SystemVerilog learning 5 (concurrent threads... Including practical exercises)
[wechat applet] Chapter (5): basic API interface of wechat applet
Please supervise the 2022 plan
Detailed explanation of unity hot update knowledge points and introduction to common solution principles
UE4 exports the picture + text combination diagram through ucanvasrendertarget2d
numpy---基础学习笔记
Three. JS introductory learning notes 19: how to import FBX static model
Steps to create P8 certificate and warehousing account
Summary of knowledge points of xlua hot update solution
Getting started with webgl (1)
What is Base64?
Three. JS introductory learning notes 0: illustration of how webgl and threejs work
How to create Apple Developer personal account P8 certificate
AB package details in unity (super detail, features, packaging, loading, manager)
Three. JS introductory learning notes 00: coordinate system, camera (temporarily understood)
Apache Doris刚“毕业”:为什么应关注这种SQL数据仓库?
Syntax of generator function (state machine)
leetcode 241. Different Ways to Add Parentheses 为运算表达式设计优先级(中等)