Unity版本:2017.4
简介: UGUI使用ScrollView、GridLayoutGroup实现无限循环列表,支持数据刷新,支持跳转,支持动态插入/删除
使用说明: 点击UI中的ID进行删除,键盘按下A添加ID。 在Inspector面板中输入MaxItemCount 列表最大数量。TargetID输入要跳转的ID,键盘按下Space跳转到要查找的ID。
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的挂载
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实现
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