Compare commits
2 Commits
b6dacac94d
...
ff545585d7
| Author | SHA1 | Date | |
|---|---|---|---|
| ff545585d7 | |||
| a5c64c2d49 |
@ -37,6 +37,8 @@ namespace AlicizaX.UI
|
||||
set => SetChoiceIndex(value);
|
||||
}
|
||||
|
||||
internal Action<int> OnChoiceIndexChanged;
|
||||
|
||||
public Adapter(RecyclerView recyclerView) : this(recyclerView, new List<T>())
|
||||
{
|
||||
}
|
||||
@ -383,6 +385,8 @@ namespace AlicizaX.UI
|
||||
{
|
||||
UpdateSelectionState(newHolder, true);
|
||||
}
|
||||
|
||||
OnChoiceIndexChanged?.Invoke(choiceIndex);
|
||||
}
|
||||
|
||||
protected virtual bool TryGetBindData(int index, out T data)
|
||||
|
||||
@ -26,6 +26,11 @@ namespace AlicizaX.UI
|
||||
return showList.Count;
|
||||
}
|
||||
|
||||
public override int GetRealCount()
|
||||
{
|
||||
return showList.Count;
|
||||
}
|
||||
|
||||
public override string GetViewName(int index)
|
||||
{
|
||||
return index >= 0 && index < showList.Count
|
||||
@ -60,10 +65,10 @@ namespace AlicizaX.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
Collapse(i);
|
||||
CollapseInternal(i);
|
||||
if (group.Expanded)
|
||||
{
|
||||
Expand(i);
|
||||
ExpandInternal(i);
|
||||
i += CountItemsForType(group.Type);
|
||||
}
|
||||
}
|
||||
@ -93,6 +98,47 @@ namespace AlicizaX.UI
|
||||
}
|
||||
|
||||
public void Expand(int index)
|
||||
{
|
||||
SetExpanded(index, true);
|
||||
}
|
||||
|
||||
public void Collapse(int index)
|
||||
{
|
||||
SetExpanded(index, false);
|
||||
}
|
||||
|
||||
public bool SetExpanded(int index, bool expanded)
|
||||
{
|
||||
if (!TryGetDisplayData(index, out TData data) || !IsGroupIndex(index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
data.Expanded = expanded;
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsGroupIndex(int index)
|
||||
{
|
||||
return index >= 0 &&
|
||||
index < showList.Count &&
|
||||
string.Equals(showList[index].TemplateName, groupViewName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public bool TryGetDisplayData(int index, out TData data)
|
||||
{
|
||||
if (list == null || index < 0 || index >= showList.Count)
|
||||
{
|
||||
data = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
data = showList[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ExpandInternal(int index)
|
||||
{
|
||||
if (list == null || index < 0 || index >= showList.Count)
|
||||
{
|
||||
@ -110,7 +156,7 @@ namespace AlicizaX.UI
|
||||
}
|
||||
}
|
||||
|
||||
public void Collapse(int index)
|
||||
private void CollapseInternal(int index)
|
||||
{
|
||||
if (index < 0 || index >= showList.Count)
|
||||
{
|
||||
@ -155,10 +201,9 @@ namespace AlicizaX.UI
|
||||
}
|
||||
|
||||
TData data = showList[index];
|
||||
if (data.TemplateName == groupViewName)
|
||||
if (IsGroupIndex(index))
|
||||
{
|
||||
data.Expanded = !data.Expanded;
|
||||
NotifyDataChanged();
|
||||
SetExpanded(index, !data.Expanded);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -413,7 +413,7 @@ namespace AlicizaX.UI
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前记录的内部逻辑索引。
|
||||
/// 仅供框架内部的导航与布局逻辑使用;业务层请改用 <see cref="OnIndexChanged"/> 维护自身状态,
|
||||
/// 仅供框架内部的导航与布局逻辑使用;业务层请改用 <see cref="OnFocusIndexChanged"/> 维护自身状态,
|
||||
/// 或使用适配器上的 <c>ChoiceIndex</c> 表示业务选中项。
|
||||
/// </summary>
|
||||
internal int CurrentIndex => currentIndex;
|
||||
@ -425,12 +425,22 @@ namespace AlicizaX.UI
|
||||
/// <summary>
|
||||
/// 当当前逻辑索引发生变化时触发。
|
||||
/// </summary>
|
||||
public Action<int> OnIndexChanged;
|
||||
public Action<int> OnFocusIndexChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 当滚动位置发生变化时触发。
|
||||
/// </summary>
|
||||
public Action OnScrollValueChanged;
|
||||
public Action<float> OnScrollValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 当滚动停止时触发。
|
||||
/// </summary>
|
||||
public Action OnScrollStopped;
|
||||
|
||||
/// <summary>
|
||||
/// 当拖拽状态变化时触发。
|
||||
/// </summary>
|
||||
public Action<bool> OnScrollDraggingChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -532,6 +542,7 @@ namespace AlicizaX.UI
|
||||
scroller.Snap = snap;
|
||||
scroller.OnValueChanged.AddListener(OnScrollChanged);
|
||||
scroller.OnMoveStoped.AddListener(OnMoveStoped);
|
||||
scroller.OnDragging.AddListener(OnScrollerDraggingChanged);
|
||||
UpdateScrollerState();
|
||||
}
|
||||
|
||||
@ -968,10 +979,6 @@ namespace AlicizaX.UI
|
||||
|
||||
float targetPosition = CalculateScrollPositionWithAlignment(index, alignment, offset);
|
||||
|
||||
if (UGListExtensions.DebugScrollTo)
|
||||
{
|
||||
Debug.Log($"[RecyclerView] ScrollToWithAlignment: index={index}, alignment={alignment}, offset={offset}, targetPosition={targetPosition}, maxPosition={scroller.MaxPosition}");
|
||||
}
|
||||
|
||||
if (duration > 0 && smooth)
|
||||
{
|
||||
@ -1022,11 +1029,6 @@ namespace AlicizaX.UI
|
||||
// 叠加调用方传入的额外偏移量。
|
||||
targetPosition += offset;
|
||||
|
||||
if (UGListExtensions.DebugScrollTo)
|
||||
{
|
||||
Debug.Log($"[RecyclerView] CalculateScrollPosition: index={index}, itemPosition={itemPosition}, itemSize={itemSize}, viewportLength={viewportLength}, contentLength={contentLength}, targetPosition={targetPosition}, maxPosition={scroller.MaxPosition}");
|
||||
}
|
||||
|
||||
// 将结果限制在可滚动范围内。
|
||||
return Mathf.Clamp(targetPosition, 0, scroller.MaxPosition);
|
||||
}
|
||||
@ -1074,7 +1076,7 @@ namespace AlicizaX.UI
|
||||
UpdateScrollbarValue(position);
|
||||
UpdateVisibleRange();
|
||||
layoutManager.DoItemAnimation();
|
||||
OnScrollValueChanged?.Invoke();
|
||||
OnScrollValueChanged?.Invoke(position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1088,6 +1090,16 @@ namespace AlicizaX.UI
|
||||
}
|
||||
|
||||
TryProcessPendingFocusRequest();
|
||||
OnScrollStopped?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 响应滚动器拖拽状态变化。
|
||||
/// </summary>
|
||||
/// <param name="dragging">当前是否正在拖拽。</param>
|
||||
private void OnScrollerDraggingChanged(bool dragging)
|
||||
{
|
||||
OnScrollDraggingChanged?.Invoke(dragging);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1410,7 +1422,7 @@ namespace AlicizaX.UI
|
||||
if (currentIndex != -1)
|
||||
{
|
||||
currentIndex = -1;
|
||||
OnIndexChanged?.Invoke(currentIndex);
|
||||
OnFocusIndexChanged?.Invoke(currentIndex);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1422,7 +1434,7 @@ namespace AlicizaX.UI
|
||||
if (currentIndex != index)
|
||||
{
|
||||
currentIndex = index;
|
||||
OnIndexChanged?.Invoke(currentIndex);
|
||||
OnFocusIndexChanged?.Invoke(currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,36 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace AlicizaX.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 封装 RecyclerView 与 Adapter 的通用列表基类。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">列表数据类型。</typeparam>
|
||||
/// <typeparam name="TAdapter">适配器类型。</typeparam>
|
||||
public abstract class UGListBase<TData, TAdapter> where TAdapter : Adapter<TData> where TData : ISimpleViewData
|
||||
public abstract class UGListBase<TData, TAdapter>
|
||||
where TAdapter : Adapter<TData>
|
||||
where TData : ISimpleViewData
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联的 RecyclerView 实例。
|
||||
/// </summary>
|
||||
protected readonly RecyclerView _recyclerView;
|
||||
|
||||
/// <summary>
|
||||
/// 当前列表使用的适配器实例。
|
||||
/// </summary>
|
||||
protected readonly TAdapter _adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前绑定的 RecyclerView。
|
||||
/// </summary>
|
||||
public RecyclerView RecyclerView => _recyclerView;
|
||||
private List<TData> _datas;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化列表封装并将适配器绑定到 RecyclerView。
|
||||
/// </summary>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
/// <param name="adapter">用于驱动列表渲染的适配器。</param>
|
||||
public UGListBase(RecyclerView recyclerView, TAdapter adapter)
|
||||
protected UGListBase(RecyclerView recyclerView, TAdapter adapter)
|
||||
{
|
||||
_recyclerView = recyclerView;
|
||||
_adapter = adapter;
|
||||
@ -41,60 +24,10 @@ namespace AlicizaX.UI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前列表使用的适配器。
|
||||
/// </summary>
|
||||
public RecyclerView RecyclerView => _recyclerView;
|
||||
|
||||
public TAdapter Adapter => _adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 注册指定视图类型对应的 ItemRender。
|
||||
/// </summary>
|
||||
/// <typeparam name="TItemRender">ItemRender 类型。</typeparam>
|
||||
/// <param name="viewName">视图名称;为空时表示默认视图。</param>
|
||||
public void RegisterItemRender<TItemRender>(string viewName = "") where TItemRender : ItemRenderBase
|
||||
{
|
||||
_adapter.RegisterItemRender<TItemRender>(viewName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按运行时类型注册指定视图对应的 ItemRender。
|
||||
/// </summary>
|
||||
/// <param name="itemRenderType">ItemRender 的运行时类型。</param>
|
||||
/// <param name="viewName">视图名称;为空时表示默认视图。</param>
|
||||
public void RegisterItemRender(Type itemRenderType, string viewName = "")
|
||||
{
|
||||
_adapter.RegisterItemRender(itemRenderType, viewName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注销指定视图名称对应的 ItemRender 注册。
|
||||
/// </summary>
|
||||
/// <param name="viewName">视图名称;为空时表示默认视图。</param>
|
||||
/// <returns>是否成功移除对应注册。</returns>
|
||||
public bool UnregisterItemRender(string viewName = "")
|
||||
{
|
||||
return _adapter.UnregisterItemRender(viewName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空当前列表的全部 ItemRender 注册信息。
|
||||
/// </summary>
|
||||
public void ClearItemRenderRegistrations()
|
||||
{
|
||||
_adapter.ClearItemRenderRegistrations();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前持有的数据集合引用。
|
||||
/// </summary>
|
||||
private List<TData> _datas;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当前列表数据。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 设置数据时会同步调用适配器刷新列表内容。
|
||||
/// </remarks>
|
||||
public List<TData> Data
|
||||
{
|
||||
get => _datas;
|
||||
@ -104,112 +37,288 @@ namespace AlicizaX.UI
|
||||
_adapter.SetList(_datas);
|
||||
}
|
||||
}
|
||||
|
||||
public int DataCount => _datas?.Count ?? 0;
|
||||
|
||||
public int FocusIndex => _recyclerView != null ? _recyclerView.CurrentIndex : -1;
|
||||
|
||||
public int ChoiceIndex
|
||||
{
|
||||
get => _adapter != null ? _adapter.ChoiceIndex : -1;
|
||||
set
|
||||
{
|
||||
if (_adapter != null)
|
||||
{
|
||||
_adapter.ChoiceIndex = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasChoice => ChoiceIndex >= 0;
|
||||
|
||||
public float ScrollPosition => _recyclerView != null ? _recyclerView.GetScrollPosition() : 0f;
|
||||
|
||||
public event Action<int> OnFocusIndexChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnFocusIndexChanged += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnFocusIndexChanged -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<int> OnChoiceIndexChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_adapter != null)
|
||||
{
|
||||
_adapter.OnChoiceIndexChanged += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (_adapter != null)
|
||||
{
|
||||
_adapter.OnChoiceIndexChanged -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<float> ScrollValueChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnScrollValueChanged += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnScrollValueChanged -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action ScrollStopped
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnScrollStopped += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnScrollStopped -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<bool> ScrollDraggingChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnScrollDraggingChanged += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (_recyclerView != null)
|
||||
{
|
||||
_recyclerView.OnScrollDraggingChanged -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterItemRender<TItemRender>(string viewName = "") where TItemRender : ItemRenderBase
|
||||
{
|
||||
_adapter.RegisterItemRender<TItemRender>(viewName);
|
||||
}
|
||||
|
||||
public void RegisterItemRender(Type itemRenderType, string viewName = "")
|
||||
{
|
||||
_adapter.RegisterItemRender(itemRenderType, viewName);
|
||||
}
|
||||
|
||||
public bool UnregisterItemRender(string viewName = "")
|
||||
{
|
||||
return _adapter.UnregisterItemRender(viewName);
|
||||
}
|
||||
|
||||
public void ClearItemRenderRegistrations()
|
||||
{
|
||||
_adapter.ClearItemRenderRegistrations();
|
||||
}
|
||||
|
||||
public void ClearChoice()
|
||||
{
|
||||
ChoiceIndex = -1;
|
||||
}
|
||||
|
||||
public bool TryFocus(int index, bool smooth = false, ScrollAlignment alignment = ScrollAlignment.Center)
|
||||
{
|
||||
return _recyclerView != null && _recyclerView.TryFocusIndex(index, smooth, alignment);
|
||||
}
|
||||
|
||||
public bool TryFocusChoice(bool smooth = false, ScrollAlignment alignment = ScrollAlignment.Center)
|
||||
{
|
||||
int index = ChoiceIndex;
|
||||
return index >= 0 && TryFocus(index, smooth, alignment);
|
||||
}
|
||||
|
||||
public bool TryFocusEntry(MoveDirection entryDirection)
|
||||
{
|
||||
return _recyclerView != null && _recyclerView.TryFocusEntry(entryDirection);
|
||||
}
|
||||
|
||||
public void ScrollToIndex(int index, bool smooth = false)
|
||||
{
|
||||
_recyclerView?.ScrollTo(index, smooth);
|
||||
}
|
||||
|
||||
public void ScrollTo(
|
||||
int index,
|
||||
ScrollAlignment alignment = ScrollAlignment.Start,
|
||||
float offset = 0f,
|
||||
bool smooth = false,
|
||||
float duration = 0.3f)
|
||||
{
|
||||
_recyclerView?.ScrollToWithAlignment(index, alignment, offset, smooth, duration);
|
||||
}
|
||||
|
||||
public void ScrollToChoice(
|
||||
ScrollAlignment alignment = ScrollAlignment.Center,
|
||||
float offset = 0f,
|
||||
bool smooth = false,
|
||||
float duration = 0.3f)
|
||||
{
|
||||
int index = ChoiceIndex;
|
||||
if (index >= 0)
|
||||
{
|
||||
ScrollTo(index, alignment, offset, smooth, duration);
|
||||
}
|
||||
}
|
||||
|
||||
public void ScrollToFocus(
|
||||
ScrollAlignment alignment = ScrollAlignment.Center,
|
||||
float offset = 0f,
|
||||
bool smooth = false,
|
||||
float duration = 0.3f)
|
||||
{
|
||||
int index = FocusIndex;
|
||||
if (index >= 0)
|
||||
{
|
||||
ScrollTo(index, alignment, offset, smooth, duration);
|
||||
}
|
||||
}
|
||||
|
||||
public void ScrollToStart(int index, float offset = 0f, bool smooth = false, float duration = 0.3f)
|
||||
{
|
||||
ScrollTo(index, ScrollAlignment.Start, offset, smooth, duration);
|
||||
}
|
||||
|
||||
public void ScrollToCenter(int index, float offset = 0f, bool smooth = false, float duration = 0.3f)
|
||||
{
|
||||
ScrollTo(index, ScrollAlignment.Center, offset, smooth, duration);
|
||||
}
|
||||
|
||||
public void ScrollToEnd(int index, float offset = 0f, bool smooth = false, float duration = 0.3f)
|
||||
{
|
||||
ScrollTo(index, ScrollAlignment.End, offset, smooth, duration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提供单模板列表的便捷封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">列表数据类型。</typeparam>
|
||||
public class UGList<TData> : UGListBase<TData, Adapter<TData>> where TData : ISimpleViewData
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化单模板列表。
|
||||
/// </summary>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
public UGList(RecyclerView recyclerView)
|
||||
: base(recyclerView, new Adapter<TData>(recyclerView))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提供分组列表的便捷封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">分组列表数据类型。</typeparam>
|
||||
public class UGGroupList<TData> : UGListBase<TData, GroupAdapter<TData>> where TData : class, IGroupViewData, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化分组列表。
|
||||
/// </summary>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
/// <param name="groupViewName">分组头使用的模板名称。</param>
|
||||
public UGGroupList(RecyclerView recyclerView, string groupViewName)
|
||||
: base(recyclerView, new GroupAdapter<TData>(recyclerView, groupViewName))
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsGroupIndex(int index)
|
||||
{
|
||||
return _adapter.IsGroupIndex(index);
|
||||
}
|
||||
|
||||
public bool TryGetDisplayData(int index, out TData data)
|
||||
{
|
||||
return _adapter.TryGetDisplayData(index, out data);
|
||||
}
|
||||
|
||||
public bool SetExpanded(int index, bool expanded)
|
||||
{
|
||||
return _adapter.SetExpanded(index, expanded);
|
||||
}
|
||||
|
||||
public void Expand(int index)
|
||||
{
|
||||
_adapter.Expand(index);
|
||||
}
|
||||
|
||||
public void Collapse(int index)
|
||||
{
|
||||
_adapter.Collapse(index);
|
||||
}
|
||||
|
||||
public void Activate(int index)
|
||||
{
|
||||
_adapter.Activate(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提供循环列表的便捷封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">循环列表数据类型。</typeparam>
|
||||
public class UGLoopList<TData> : UGListBase<TData, LoopAdapter<TData>> where TData : ISimpleViewData, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化循环列表。
|
||||
/// </summary>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
public UGLoopList(RecyclerView recyclerView)
|
||||
: base(recyclerView, new LoopAdapter<TData>(recyclerView))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提供多模板列表的便捷封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">多模板列表数据类型。</typeparam>
|
||||
public class UGMixedList<TData> : UGListBase<TData, MixedAdapter<TData>> where TData : IMixedViewData
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化多模板列表。
|
||||
/// </summary>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
public UGMixedList(RecyclerView recyclerView)
|
||||
: base(recyclerView, new MixedAdapter<TData>(recyclerView))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提供常用 UGList 类型的快速创建方法。
|
||||
/// </summary>
|
||||
public static class UGListCreateHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建单模板列表封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">列表数据类型。</typeparam>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
/// <returns>创建后的单模板列表实例。</returns>
|
||||
public static UGList<TData> Create<TData>(RecyclerView recyclerView) where TData : ISimpleViewData
|
||||
=> new UGList<TData>(recyclerView);
|
||||
|
||||
/// <summary>
|
||||
/// 创建分组列表封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">分组列表数据类型。</typeparam>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
/// <param name="groupViewName">分组头使用的模板名称。</param>
|
||||
/// <returns>创建后的分组列表实例。</returns>
|
||||
public static UGGroupList<TData> CreateGroup<TData>(RecyclerView recyclerView, string groupViewName) where TData : class, IGroupViewData, new()
|
||||
=> new UGGroupList<TData>(recyclerView, groupViewName);
|
||||
|
||||
/// <summary>
|
||||
/// 创建循环列表封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">循环列表数据类型。</typeparam>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
/// <returns>创建后的循环列表实例。</returns>
|
||||
public static UGLoopList<TData> CreateLoop<TData>(RecyclerView recyclerView) where TData : ISimpleViewData, new()
|
||||
=> new UGLoopList<TData>(recyclerView);
|
||||
|
||||
/// <summary>
|
||||
/// 创建多模板列表封装。
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">多模板列表数据类型。</typeparam>
|
||||
/// <param name="recyclerView">目标 RecyclerView。</param>
|
||||
/// <returns>创建后的多模板列表实例。</returns>
|
||||
public static UGMixedList<TData> CreateMixed<TData>(RecyclerView recyclerView) where TData : IMixedViewData
|
||||
=> new UGMixedList<TData>(recyclerView);
|
||||
}
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd094e3cb2194cb193221ea9436a169a
|
||||
timeCreated: 1766729620
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@ -8,9 +8,6 @@ namespace AlicizaX.UI
|
||||
/// </summary>
|
||||
public static class UGListExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 控制是否输出滚动定位调试日志。
|
||||
/// </summary>
|
||||
public static bool DebugScrollTo { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
@ -40,12 +37,7 @@ namespace AlicizaX.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (DebugScrollTo)
|
||||
{
|
||||
Debug.Log($"[UGListExtensions] ScrollTo: index={index}, alignment={alignment}, offset={offset}, smooth={smooth}, duration={duration}");
|
||||
}
|
||||
|
||||
ugList.RecyclerView.ScrollToWithAlignment(index, alignment, offset, smooth, duration);
|
||||
ugList.ScrollTo(index, alignment, offset, smooth, duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -67,7 +59,7 @@ namespace AlicizaX.UI
|
||||
where TAdapter : Adapter<TData>
|
||||
where TData : ISimpleViewData
|
||||
{
|
||||
ugList.ScrollTo(index, ScrollAlignment.Start, offset, smooth, duration);
|
||||
ugList.ScrollToStart(index, offset, smooth, duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -89,7 +81,7 @@ namespace AlicizaX.UI
|
||||
where TAdapter : Adapter<TData>
|
||||
where TData : ISimpleViewData
|
||||
{
|
||||
ugList.ScrollTo(index, ScrollAlignment.Center, offset, smooth, duration);
|
||||
ugList.ScrollToCenter(index, offset, smooth, duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -111,7 +103,7 @@ namespace AlicizaX.UI
|
||||
where TAdapter : Adapter<TData>
|
||||
where TData : ISimpleViewData
|
||||
{
|
||||
ugList.ScrollTo(index, ScrollAlignment.End, offset, smooth, duration);
|
||||
ugList.ScrollToEnd(index, offset, smooth, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user