[+] UI循环列表拓展与示例

[+] UI循环列表拓展与示例
This commit is contained in:
ALEXTANG
2023-08-10 23:25:43 +08:00
parent ea9447d0ea
commit 53f0ecb6c1
22 changed files with 4700 additions and 558 deletions

View File

@@ -0,0 +1,337 @@
using System;
using System.Collections.Generic;
using TEngine;
using UnityEngine;
using UnityEngine.UI;
namespace GameLogic
{
/// <summary>
/// UI列表Item
/// </summary>
/// <typeparam name="DataT"></typeparam>
public interface IListDataItem<in DataT>
{
void SetItemData(DataT d);
}
/// <summary>
/// UI列表Item
/// </summary>
public interface IListSelectItem
{
/// <summary>
/// 获取索引。
/// </summary>
/// <returns></returns>
int GetItemIndex();
/// <summary>
/// 设置索引。
/// </summary>
/// <param name="i"></param>
void SetItemIndex(int i);
/// <summary>
/// 是否被选中。
/// </summary>
/// <returns></returns>
bool IsSelected();
/// <summary>
/// 设置是否选中。
/// </summary>
/// <param name="v"></param>
void SetSelected(bool v);
}
public class SelectItemBase : UIEventItem<SelectItemBase>, IListSelectItem
{
/// <summary>
/// 索引。
/// </summary>
protected int m_itemIndex;
public int GetItemIndex()
{
return m_itemIndex;
}
public void SetItemIndex(int i)
{
m_itemIndex = i;
}
/// <summary>
/// 是否被选中。
/// </summary>
protected bool m_isSelected;
public virtual bool IsSelected()
{
return m_isSelected;
}
public virtual void SetSelected(bool v)
{
if (m_isSelected == v) return;
m_isSelected = v;
UpdateSelect();
}
/// <summary>
/// 刷新选中状态。
/// </summary>
public virtual void UpdateSelect()
{
}
public override void RegisterEvent()
{
base.RegisterEvent();
AddSelectEvt();
}
/// <summary>
/// 监听选中事件。
/// </summary>
protected virtual void AddSelectEvt()
{
if (Parent == null || !(Parent is IUISelectList)) return;
var btn = TEngine.DUnityUtil.AddMonoBehaviour<Button>(gameObject);
if (btn != null)
{
btn.onClick.AddListener(OnSelectClick);
}
}
/// <summary>
/// 选中点击
/// </summary>
protected virtual void OnSelectClick()
{
var p = Parent as IUISelectList;
if (p != null)
{
p.OnItemClick(this, GetItemIndex());
}
}
}
interface IUISelectList
{
void OnItemClick(object item, int i);
}
/// <summary>
/// UI列表
/// </summary>
public class UIListBase<ItemT, DataT> : UIWidget, IUISelectList where ItemT : UIWidget, new()
{
/// <summary>
/// item模板
/// </summary>
public GameObject itemBase;
/// <summary>
/// 数据列表
/// </summary>
protected List<DataT> m_datas;
/// <summary>
/// 数据列表
/// </summary>
public List<DataT> datas => m_datas;
/// <summary>
/// 数据数量
/// </summary>
public int DataNum => m_datas?.Count ?? 0;
/// <summary>
/// 数量
/// </summary>
protected int m_num;
/// <summary>
/// 数量
/// </summary>
public int num => m_num;
/// <summary>
/// 设置数据数量
/// </summary>
/// <param name="n"></param>
/// <param name="funcItem"></param>
public void SetDataNum(int n, Action<ItemT, int> funcItem = null)
{
AdjustItemNum(n, null, funcItem);
}
/// <summary>
/// 数据起始索引
/// </summary>
public int dataStartOffset = 0;
/// <summary>
/// 设置数据
/// </summary>
/// <param name="dataList"></param>
/// <param name="n"></param>
public void SetDatas(List<DataT> dataList, int n = -1)
{
AdjustItemNum(Mathf.Max(0, n >= 0 ? n : (dataList == null ? 0 : (dataList.Count - dataStartOffset))),
dataList);
}
/// <summary>
/// 设置显示数据
/// </summary>
/// <param name="n"></param>
/// <param name="datas"></param>
/// <param name="funcItem"></param>
protected virtual void AdjustItemNum(int n, List<DataT> datas = null, Action<ItemT, int> funcItem = null)
{
m_num = n;
m_datas = datas;
if (itemBase != null)
{
itemBase.SetActive(false);
}
}
/// <summary>
/// 刷新列表ITEM
/// </summary>
/// <param name="item"></param>
/// <param name="i"></param>
/// <param name="func"></param>
protected virtual void UpdateListItem(ItemT item, int i, Action<ItemT, int> func)
{
if (item == null) return;
if (func != null)
{
func.Invoke(item, i);
return;
}
var listDataItem = item as IListDataItem<DataT>;
if (listDataItem != null)
{
listDataItem.SetItemData(GetData(i));
}
}
/// <summary>
/// 选中索引
/// </summary>
protected int m_selectIndex = -1;
/// <summary>
/// Item点击
/// </summary>
public Action<int> funcOnItemClick;
/// <summary>
/// 选中变化回调函数
/// </summary>
public Action funcOnSelectChange;
/// <summary>
/// 点击无选中变化回调
/// </summary>
public Action funcNoSelectChange;
/// <summary>
/// 选中索引
/// </summary>
public int selectIndex
{
get => m_selectIndex;
set => SetSelectIndex(value);
}
/// <summary>
/// 设置选中索引
/// </summary>
/// <param name="i"></param>
/// <param name="forceUpdate"></param>
/// <param name="triggerEvt"></param>
public void SetSelectIndex(int i, bool forceUpdate = false, bool triggerEvt = true)
{
if (!forceUpdate && m_selectIndex == i)
{
if (funcNoSelectChange != null)
{
funcNoSelectChange.Invoke();
}
return;
}
var preIndex = selectIndex;
m_selectIndex = i;
var item = GetItem(preIndex) as IListSelectItem;
if (item != null)
{
item.SetSelected(false);
}
item = GetItem(selectIndex) as IListSelectItem;
if (item != null)
{
item.SetSelected(true);
}
if (triggerEvt && funcOnSelectChange != null)
{
funcOnSelectChange.Invoke();
}
}
/// <summary>
/// 获取当前选中的数据
/// </summary>
/// <returns></returns>
public DataT GetSelectData()
{
return GetData(selectIndex);
}
/// <summary>
/// 获取数据
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public DataT GetData(int i)
{
i += dataStartOffset;
return m_datas == null || i < 0 || i >= m_datas.Count ? default(DataT) : m_datas[i];
}
/// <summary>
/// 获取item
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public virtual ItemT GetItem(int i)
{
return null;
}
/// <summary>
/// item被点击
/// </summary>
/// <param name="item"></param>
/// <param name="i"></param>
public void OnItemClick(object item, int i)
{
if (funcOnItemClick != null)
{
funcOnItemClick.Invoke(i);
}
selectIndex = i;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9d3742a744bb4934a4848b54bb6910a2
timeCreated: 1691679426

View File

@@ -0,0 +1,14 @@
namespace GameLogic
{
public class UILoopItemWidget : SelectItemBase
{
public LoopListViewItem LoopItem { set; get; }
public int Index { private set; get; }
public virtual void UpdateItem(int index)
{
Index = index;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b39b2f052eec4a4a97256e5aeee9e7dc
timeCreated: 1691679577

View File

@@ -0,0 +1,95 @@
using System.Collections.Generic;
using TEngine;
using UnityEngine;
namespace GameLogic
{
public class UILoopListViewWidget<T> : UIWidget where T : UILoopItemWidget, new()
{
public LoopListView LoopRectView { private set; get; }
private Dictionary<int, T> m_itemCache = new Dictionary<int, T>();
public override void BindMemberProperty()
{
base.BindMemberProperty();
LoopRectView = this.rectTransform.GetComponent<LoopListView>();
}
public override void OnDestroy()
{
base.OnDestroy();
m_itemCache.Clear();
}
public T CreateItem()
{
string typeName = typeof(T).Name;
return CreateItem(typeName);
;
}
public T CreateItem(string itemName)
{
T widget = null;
var item = LoopRectView.AllocOrNewListViewItem(itemName);
if (item != null)
{
widget = CreateItem(item);
}
return widget;
}
public T CreateItem(GameObject prefab)
{
T widget = null;
var item = LoopRectView.AllocOrNewListViewItem(prefab);
if (item != null)
{
widget = CreateItem(item);
}
return widget;
}
private T CreateItem(LoopListViewItem item)
{
T widget;
if (!m_itemCache.TryGetValue(item.GoId, out widget))
{
widget = CreateWidget<T>(item.gameObject);
widget.LoopItem = item;
m_itemCache.Add(item.GoId, widget);
}
return widget;
}
public List<T> GetItemList()
{
List<T> list = new List<T>();
for (int i = 0; i < m_itemCache.Count; i++)
{
list.Add(m_itemCache[i]);
}
return list;
}
public int GetItemCount()
{
return m_itemCache.Count;
}
/// <summary>
/// 获取Item。
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T GetItemByIndex(int index)
{
return m_itemCache[index];
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9b87126ba47740708bc82eb0bb9e414e
timeCreated: 1691679617

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace GameLogic
{
/// <summary>
/// UI列表。
/// </summary>
public class UILoopListWidget<ItemT, DataT> : UIListBase<ItemT, DataT> where ItemT : UILoopItemWidget, new()
{
/// <summary>
/// LoopRectView
/// </summary>
public LoopListView LoopRectView { private set; get; }
/// <summary>
/// Item字典
/// </summary>
private Dictionary<int, ItemT> m_itemCache = new Dictionary<int, ItemT>();
/// <summary>
/// 计算偏差后的ItemList
/// </summary>
private List<ItemT> m_items = new List<ItemT>();
/// <summary>
/// 计算偏差后的ItemList
/// </summary>
public List<ItemT> items => m_items;
public override void BindMemberProperty()
{
base.BindMemberProperty();
LoopRectView = rectTransform.GetComponent<LoopListView>();
}
public override void OnCreate()
{
base.OnCreate();
LoopRectView.InitListView(0, OnGetItemByIndex);
}
public override void OnDestroy()
{
base.OnDestroy();
m_itemCache.Clear();
}
/// <summary>
/// Item回调函数
/// </summary>
protected Action<ItemT, int> m_tpFuncItem;
/// <summary>
/// 设置显示数据
/// </summary>
/// <param name="n"></param>
/// <param name="datas"></param>
/// <param name="funcItem"></param>
protected override void AdjustItemNum(int n, List<DataT> datas = null, Action<ItemT, int> funcItem = null)
{
base.AdjustItemNum(n, datas, funcItem);
m_tpFuncItem = funcItem;
LoopRectView.SetListItemCount(n);
LoopRectView.RefreshAllShownItem();
m_tpFuncItem = null;
}
/// <summary>
/// 获取Item
/// </summary>
/// <param name="listView"></param>
/// <param name="index"></param>
/// <returns></returns>
protected LoopListViewItem OnGetItemByIndex(LoopListView listView, int index)
{
if (index < 0 || index >= num) return null;
var item = itemBase == null ? CreateItem() : CreateItem(itemBase);
if (item == null) return null;
item.SetItemIndex(index);
UpdateListItem(item, index, m_tpFuncItem);
return item.LoopItem;
}
/// <summary>
/// 创建Item
/// </summary>
/// <returns></returns>
public ItemT CreateItem()
{
return CreateItem(typeof(ItemT).Name);
}
/// <summary>
/// 创建Item
/// </summary>
/// <param name="itemName"></param>
/// <returns></returns>
public ItemT CreateItem(string itemName)
{
ItemT widget = null;
LoopListViewItem item = LoopRectView.AllocOrNewListViewItem(itemName);
if (item != null)
{
widget = CreateItem(item);
}
return widget;
}
/// <summary>
/// 创建Item
/// </summary>
/// <param name="prefab"></param>
/// <returns></returns>
public ItemT CreateItem(GameObject prefab)
{
ItemT widget = null;
LoopListViewItem item = LoopRectView.AllocOrNewListViewItem(prefab);
if (item != null)
{
widget = CreateItem(item);
}
return widget;
}
/// <summary>
/// 创建Item
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
private ItemT CreateItem(LoopListViewItem item)
{
ItemT widget;
if (!m_itemCache.TryGetValue(item.GoId, out widget))
{
widget = CreateWidget<ItemT>(item.gameObject);
widget.LoopItem = item;
m_itemCache.Add(item.GoId, widget);
}
return widget;
}
/// <summary>
/// 获取item
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public override ItemT GetItem(int i)
{
return i >= 0 && i < m_items.Count ? m_items[i] : null;
}
/// <summary>
/// 获取itemList
/// </summary>
/// <returns></returns>
public List<ItemT> GetItemList()
{
m_items.Clear();
for (int i = 0; i < m_itemCache.Count; i++)
{
m_items.Add(m_itemCache[i]);
}
return m_items;
}
/// <summary>
/// 获取当前起始索引
/// </summary>
/// <returns></returns>
public int GetItemStartIndex()
{
return LoopRectView.GetItemStartIndex();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 72b7444fb04642039aacc2db27dd002a
timeCreated: 1691679907