当前位置:网站首页>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 :
边栏推荐
- Android -- jetpack: the difference between livedata setValue and postvalue
- Mysql database backup script
- Three. JS introductory learning notes 07: external model import -c4d to JSON file for web pages -fbx import
- Webgl texture
- After UE4 is packaged, mesh has no material problem
- Clang compile link ffmpeg FAQ
- Getting started with webgl (3)
- [quick start of Digital IC Verification] 19. Basic grammar of SystemVerilog learning 6 (thread internal communication... Including practical exercises)
- [wechat applet] Chapter (5): basic API interface of wechat applet
- 星瑞格数据库入围“2021年度福建省信息技术应用创新典型解决方案”
猜你喜欢
Three. JS introductory learning notes 03: perspective projection camera
A wave of open source notebooks is coming
unnamed prototyped parameters not allowed when body is present
How does geojson data merge the boundaries of regions?
TS as a general cache method
When opening the system window under UE4 shipping, the problem of crash is attached with the plug-in download address
The difference between full-time graduate students and part-time graduate students!
Streaming end, server end, player end
SPI master rx time out中断
【數字IC驗證快速入門】20、SystemVerilog學習之基本語法7(覆蓋率驅動...內含實踐練習)
随机推荐
Asynchronous application of generator function
Use of SVN
Yunxiaoduo software internal test distribution test platform description document
C4D learning notes 3- animation - animation rendering process case
It's different for rich people to buy a house
Getting started with webgl (3)
Keil5 does not support online simulation of STM32 F0 series
Vertex shader to slice shader procedure, varying variable
There are many ways to realize the pause function in JS
Cocos uses custom material to display problems
A link opens the applet code. After compilation, it is easy to understand
SPI master rx time out中断
[quick start of Digital IC Verification] 26. Ahb-sramc of SystemVerilog project practice (6) (basic points of APB protocol)
Spin animation of Cocos performance optimization
AE learning 02: timeline
[Lanzhou University] information sharing of postgraduate entrance examination and re examination
After UE4 is packaged, mesh has no material problem
Vite path alias @ configuration
Detailed explanation of unity hot update knowledge points and introduction to common solution principles
Align individual elements to the right under flex layout