using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//Introduction: 无限列表
//Content上禁止挂载ContentSizeFilter和LayOutGroup之类组件
[DisallowMultipleComponent]
[RequireComponent(typeof(ScrollRect))]
public class UIGridView : MonoBehaviour
{
private Action _handle;
public enum Arrangement
{
Horizontal = 0,
Vertical,
}
public enum HorizontalAlign
{
Left,
Middle,
Right,
}
public enum VerticalAlign
{
Top,
Middle,
Bottom,
}
public Arrangement arrangement = Arrangement.Vertical;
// 当选择水平或垂直流动是有用,指每行/列最大个数
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; //需要渲染的总数据个数
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 items;
Dictionary contains;
List outOfContains;
int scrollLineIndex; //当前第一个元素索引
int totalCount; //在UI中显示的个数(不乘以maxPerLine)
Vector2 startPos; //第一个元素所在位置
int startIndex; //当前渲染起始坐标
int endIndex; //当前渲染结束坐标
void Start()
{
maxPerLine = maxPerLine == 0 ? 1 : maxPerLine;
items = new List();
contains = new Dictionary();
outOfContains = new List();
scrollRect = transform.GetComponent();
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; //横向列数
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; //竖向行数
startPos = Vector2.zero;
startPos.y = -marginTop; //重置开始节点位置
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);
}
//列表滚动
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(); //渲染序号
outOfContains.Clear(); //items的索引
for (int i = 0; i < items.Count; i++)//如果当前已渲染的item中包含
{
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);
}
}
// *************更改渲染****************
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;
}
/// 移除当前所有
private void ResetChildren()
{
items.Clear();
for (int i = 0; i < content.childCount; i++)
{
Transform child = content.GetChild(i);
child.gameObject.SetActive(false);
}
}
// 创建新节点
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;
}
// 设置资源
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();
}
// 更新需要渲染的个数
public void SetChildCount(int value, bool forceRender)
{
if (value < 0) childCount = 0;
else childCount = value;
if (totalCount <= 0)//还未初始化
return;
if (value > items.Count && items.Count < maxPerLine * totalCount)
{
//当前格子数量少于应生成的数量
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); //设置content的大小
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);
}
// 添加子节点
public void AddChild(int index)
{
if (index < 0) return;
startIndex = scrollLineIndex * maxPerLine;
endIndex = (scrollLineIndex + totalCount) * maxPerLine;
SetChildCount(childCount + 1, index >= startIndex && index < endIndex);
}
// 删除子节点
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);
}
//
// 设置显示窗口大小(现在貌似可以废弃了)
public void SetViewPort(Vector2 port)
{
if (port == viewPort) return;
viewPort = port;
//ReBuild();
}
// 设置行列最大
public void SetMaxPerLine(int max)
{
maxPerLine = max;
//ReBuild();
}
// 返回顶部
public void BackTop()
{
content.localPosition = Vector3.zero;
UpdateRectItem(0, true);
}
// 返回底部
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 handle)
{
_handle = handle;
}
}
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, --可领取
UNREACH = 1, --未达成
FINISHED = 2, --已领取
}
function SprogExtendWindow.Init(data)
mediate = data
-- 创建ITEM实例
ResMgr.LoadAssets("prefab", { "SprogExtendItem" },function(objs)
extendItem = objs[0]
end)
extendItemInfo = {} -- 服务器下发数据
sortList = {} -- 前端已排序处理,用于显示的数据
SprogExtendWindow.InitGridView()
SprogExtendWindow.RegistEvents()
SprogExtendWindow.UpdateAllExtendInfo()
return SprogExtendWindow
end
function SprogExtendWindow.InitGridView()
gridView = mediate:FindChild("Layer_Sprite/panelGroup/extendPanel/bottom/Scroll View"):GetComponent("UIGridView") -- 获取UIGridView组件
gridView.maxPerLine = 1
gridView.rowSpace = 1
gridView:SetItem(extendItem)
gridView:SetViewPort(Vector2(565,325))
-- 在ScrollView拖动时,UIGridView会回调即将出现的item,客户端只需要填入相应的UI数据.
-- PS: 此函数会不停地调用,得考虑性能问题,避免处理过大的数据
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("按钮1")
end)
mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_link", function ()
log("按钮2")
end)
mediate:AddClick("Layer_Sprite/panelGroup/extendPanel/top/btn_share", function ()
log("按钮3")
end)
end
function SprogExtendWindow.InitScrollView()
end
function SprogExtendWindow.UpdateAllExtendInfo()
-- TEST,选用临时数据
local data =
{
[1] = {id = 1, type = 1, time = "2020.01.01", name = "床", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},
[2] = {id = 2, type = 1, time = "2020.01.02", name = "前", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},
[3] = {id = 3, type = 1, time = "2020.01.03", name = "明", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},
[4] = {id = 4, type = 1, time = "2020.01.04", name = "月", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},
[5] = {id = 5, type = 1, time = "2020.01.05", name = "光", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999},
[6] = {id = 6, type = 1, time = "2020.01.06", name = "床", img = "yxdt_tx1.png", vip = 6, liquanNum = 99999},
[7] = {id = 7, type = 1, time = "2020.01.07", name = "前", img = "yxdt_tx1.png", vip = 7, liquanNum = 99999},
[8] = {id = 8, type = 1, time = "2020.01.08", name = "明", img = "yxdt_tx1.png", vip = 8, liquanNum = 99999},
[9] = {id = 9, type = 1, time = "2020.01.09", name = "月", img = "yxdt_tx1.png", vip = 9, liquanNum = 99999},
[10] = {id = 10, type = 1, time = "2020.01.10", name = "光", img = "yxdt_tx1.png", vip = 10, liquanNum = 99999},
[11] = {id = 11, type = 1, time = "2020.01.01", name = "床", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},
[12] = {id = 12, type = 1, time = "2020.01.02", name = "前", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},
[13] = {id = 13, type = 1, time = "2020.01.03", name = "明", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},
[14] = {id = 14, type = 1, time = "2020.01.04", name = "月", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},
[15] = {id = 15, type = 1, time = "2020.01.05", name = "光", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999},
[16] = {id = 16, type = 1, time = "2020.01.06", name = "床", img = "yxdt_tx1.png", vip = 6, liquanNum = 99999},
[17] = {id = 17, type = 1, time = "2020.01.07", name = "前", img = "yxdt_tx1.png", vip = 7, liquanNum = 99999},
[18] = {id = 18, type = 1, time = "2020.01.08", name = "明", img = "yxdt_tx1.png", vip = 8, liquanNum = 99999},
[19] = {id = 19, type = 1, time = "2020.01.09", name = "月", img = "yxdt_tx1.png", vip = 9, liquanNum = 99999},
[20] = {id = 20, type = 1, time = "2020.01.10", name = "光", img = "yxdt_tx1.png", vip = 10, liquanNum = 99999},
[21] = {id = 21, type = 1, time = "2020.01.01", name = "床", img = "yxdt_tx1.png", vip = 1, liquanNum = 99999},
[22] = {id = 22, type = 1, time = "2020.01.02", name = "前", img = "yxdt_tx1.png", vip = 2, liquanNum = 99999},
[23] = {id = 23, type = 1, time = "2020.01.03", name = "明", img = "yxdt_tx1.png", vip = 3, liquanNum = 99999},
[24] = {id = 24, type = 1, time = "2020.01.04", name = "月", img = "yxdt_tx1.png", vip = 4, liquanNum = 99999},
[25] = {id = 25, type = 1, time = "2020.01.05", name = "光", img = "yxdt_tx1.png", vip = 5, liquanNum = 99999}
}
extendItemInfo = {}
for k, v in ipairs(data) do
extendItemInfo[v.id] =
{
config = v, -- 本地配置
state = math.random(0, 2) -- 随机一个状态
}
end
SprogExtendWindow.OnSortAllExtendItem()
gridView.ChildCount = #sortList -- 设置当前item总数
gridView:ReBuild() -- 启动UIGridView
end
-- 整理数据并排序
function SprogExtendWindow.OnSortAllExtendItem()
-- 按rewardState分组, 可领取>未达成>已领取
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
-- 每组按VIP等级排序
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("排序后列表 " .. tostring(sortList))
end
function SprogExtendWindow.SetStateInfo(state, obj)
local text = nil
local isInteract = nil
if state == rewardState.UNREACH then
text = "未达成"
isInteract = false
elseif state == rewardState.UNFINISH then
text = "可领取"
isInteract = true
elseif state == rewardState.FINISHED then
text = "已领取"
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("领取成功,data: " .. CC.uu.Dump(data))
item.state = 2
SprogExtendWindow.SetStateInfo(item.state, obj)
end
local reqFailed = function(err)
log("领取失败:" .. tostring(err))
end
-- 发送请求
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