305 lines
8.6 KiB
C#
305 lines
8.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace AlicizaX.UI
|
|
{
|
|
/// <summary>
|
|
/// RecyclerView 的通用适配器,支持数据绑定、选中状态和列表操作
|
|
/// </summary>
|
|
/// <typeparam name="T">数据类型,必须实现 ISimpleViewData 接口</typeparam>
|
|
public class Adapter<T> : IAdapter where T : ISimpleViewData
|
|
{
|
|
protected RecyclerView recyclerView;
|
|
|
|
protected List<T> list;
|
|
protected Action<T> onItemClick;
|
|
|
|
protected int choiceIndex = -1;
|
|
|
|
/// <summary>
|
|
/// 当前选中项的索引
|
|
/// </summary>
|
|
public int ChoiceIndex
|
|
{
|
|
get => choiceIndex;
|
|
set { SetChoiceIndex(value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 构造函数
|
|
/// </summary>
|
|
/// <param name="recyclerView">RecyclerView 实例</param>
|
|
public Adapter(RecyclerView recyclerView) : this(recyclerView, new List<T>(), null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 构造函数
|
|
/// </summary>
|
|
/// <param name="recyclerView">RecyclerView 实例</param>
|
|
/// <param name="list">数据列表</param>
|
|
public Adapter(RecyclerView recyclerView, List<T> list) : this(recyclerView, list, null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 构造函数
|
|
/// </summary>
|
|
/// <param name="recyclerView">RecyclerView 实例</param>
|
|
/// <param name="list">数据列表</param>
|
|
/// <param name="onItemClick">列表项点击回调</param>
|
|
public Adapter(RecyclerView recyclerView, List<T> list, Action<T> onItemClick)
|
|
{
|
|
this.recyclerView = recyclerView;
|
|
this.list = list;
|
|
this.onItemClick = onItemClick;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取列表项总数
|
|
/// </summary>
|
|
public virtual int GetItemCount()
|
|
{
|
|
return list == null ? 0 : list.Count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取实际数据项数量
|
|
/// </summary>
|
|
public virtual int GetRealCount()
|
|
{
|
|
return GetItemCount();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取指定索引位置的视图名称
|
|
/// </summary>
|
|
public virtual string GetViewName(int index)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 绑定视图持有者与数据
|
|
/// </summary>
|
|
public virtual void OnBindViewHolder(ViewHolder viewHolder, int index)
|
|
{
|
|
if (index < 0 || index >= GetItemCount()) return;
|
|
|
|
T data = list[index];
|
|
|
|
viewHolder.BindViewData(data);
|
|
viewHolder.BindItemClick(data, t =>
|
|
{
|
|
SetChoiceIndex(index);
|
|
onItemClick?.Invoke(data);
|
|
});
|
|
viewHolder.BindChoiceState(index == choiceIndex);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 通知数据已更改
|
|
/// </summary>
|
|
public virtual void NotifyDataChanged()
|
|
{
|
|
recyclerView.RequestLayout();
|
|
recyclerView.Refresh();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置数据列表并刷新视图
|
|
/// </summary>
|
|
/// <param name="list">新的数据列表</param>
|
|
public virtual void SetList(List<T> list)
|
|
{
|
|
this.list = list;
|
|
recyclerView.Reset();
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取指定索引的数据
|
|
/// </summary>
|
|
/// <param name="index">数据索引</param>
|
|
/// <returns>数据对象,索引无效时返回 default</returns>
|
|
public T GetData(int index)
|
|
{
|
|
if (index < 0 || index >= GetItemCount()) return default;
|
|
|
|
return list[index];
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加单个数据项
|
|
/// </summary>
|
|
/// <param name="item">要添加的数据项</param>
|
|
public void Add(T item)
|
|
{
|
|
list.Add(item);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 批量添加数据项
|
|
/// </summary>
|
|
/// <param name="collection">要添加的数据集合</param>
|
|
public void AddRange(IEnumerable<T> collection)
|
|
{
|
|
list.AddRange(collection);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 在指定位置插入数据项
|
|
/// </summary>
|
|
/// <param name="index">插入位置</param>
|
|
/// <param name="item">要插入的数据项</param>
|
|
public void Insert(int index, T item)
|
|
{
|
|
list.Insert(index, item);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 在指定位置批量插入数据项
|
|
/// </summary>
|
|
/// <param name="index">插入位置</param>
|
|
/// <param name="collection">要插入的数据集合</param>
|
|
public void InsertRange(int index, IEnumerable<T> collection)
|
|
{
|
|
list.InsertRange(index, collection);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除指定的数据项
|
|
/// </summary>
|
|
/// <param name="item">要移除的数据项</param>
|
|
public void Remove(T item)
|
|
{
|
|
int index = list.IndexOf(item);
|
|
RemoveAt(index);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除指定索引位置的数据项
|
|
/// </summary>
|
|
/// <param name="index">要移除的索引</param>
|
|
public void RemoveAt(int index)
|
|
{
|
|
if (index < 0 || index >= GetItemCount()) return;
|
|
|
|
list.RemoveAt(index);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除指定范围的数据项
|
|
/// </summary>
|
|
/// <param name="index">起始索引</param>
|
|
/// <param name="count">移除数量</param>
|
|
public void RemoveRange(int index, int count)
|
|
{
|
|
list.RemoveRange(index, count);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除所有符合条件的数据项
|
|
/// </summary>
|
|
/// <param name="match">匹配条件</param>
|
|
public void RemoveAll(Predicate<T> match)
|
|
{
|
|
list.RemoveAll(match);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清空所有数据
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
list.Clear();
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 反转指定范围的数据项顺序
|
|
/// </summary>
|
|
/// <param name="index">起始索引</param>
|
|
/// <param name="count">反转数量</param>
|
|
public void Reverse(int index, int count)
|
|
{
|
|
list.Reverse(index, count);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 反转所有数据项顺序
|
|
/// </summary>
|
|
public void Reverse()
|
|
{
|
|
list.Reverse();
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 使用指定的比较器排序数据
|
|
/// </summary>
|
|
/// <param name="comparison">比较器</param>
|
|
public void Sort(Comparison<T> comparison)
|
|
{
|
|
list.Sort(comparison);
|
|
NotifyDataChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置列表项点击回调
|
|
/// </summary>
|
|
/// <param name="onItemClick">点击回调</param>
|
|
public void SetOnItemClick(Action<T> onItemClick)
|
|
{
|
|
this.onItemClick = onItemClick;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置选中项索引
|
|
/// </summary>
|
|
/// <param name="index">要选中的索引</param>
|
|
protected void SetChoiceIndex(int index)
|
|
{
|
|
if (index == choiceIndex) return;
|
|
|
|
if (choiceIndex != -1)
|
|
{
|
|
if (TryGetViewHolder(choiceIndex, out var viewHolder))
|
|
{
|
|
viewHolder.BindChoiceState(false);
|
|
}
|
|
}
|
|
|
|
choiceIndex = index;
|
|
|
|
if (choiceIndex != -1)
|
|
{
|
|
if (TryGetViewHolder(choiceIndex, out var viewHolder))
|
|
{
|
|
viewHolder.BindChoiceState(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 尝试获取指定索引的视图持有者
|
|
/// </summary>
|
|
/// <param name="index">数据索引</param>
|
|
/// <param name="viewHolder">输出的视图持有者</param>
|
|
/// <returns>是否成功获取</returns>
|
|
private bool TryGetViewHolder(int index, out ViewHolder viewHolder)
|
|
{
|
|
viewHolder = recyclerView.ViewProvider.GetViewHolder(index);
|
|
return viewHolder != null;
|
|
}
|
|
}
|
|
}
|