This commit is contained in:
陈思海 2026-03-30 15:40:00 +08:00
parent 40080636d8
commit cddf34948d

View File

@ -13,25 +13,28 @@ namespace AlicizaX.UI
void Unbind();
}
internal interface IItemRenderInitializer
{
void Reset(ViewHolder viewHolder);
}
public abstract class ItemRender<TData, THolder> : IItemRender
, IItemRenderInitializer
where THolder : ViewHolder
{
private Action defaultClickAction;
protected ItemRender(THolder holder)
{
Holder = holder ?? throw new ArgumentNullException(nameof(holder));
CurrentIndex = -1;
}
protected THolder Holder { get; }
protected THolder Holder { get; private set; }
protected TData CurrentData { get; private set; }
protected int CurrentIndex { get; private set; }
protected int CurrentIndex { get; private set; } = -1;
protected bool IsSelected { get; private set; }
public void Bind(object data, int index, Action defaultClickAction)
{
EnsureHolder();
if (data is not TData itemData)
{
throw new InvalidCastException(
@ -47,20 +50,22 @@ namespace AlicizaX.UI
public void UpdateSelection(bool selected)
{
EnsureHolder();
IsSelected = selected;
OnSelectionChanged(selected);
}
public void Unbind()
{
OnClear();
CurrentData = default;
CurrentIndex = -1;
defaultClickAction = null;
Holder.ClearInteractionCallbacks();
ResetState();
}
protected abstract void Bind(TData data, int index);
protected virtual void OnHolderChanged()
{
}
protected virtual void OnSelectionChanged(bool selected)
{
}
@ -96,19 +101,63 @@ namespace AlicizaX.UI
{
OnPointerExit();
}
void IItemRenderInitializer.Reset(ViewHolder viewHolder)
{
if (viewHolder == null)
{
throw new ArgumentNullException(nameof(viewHolder));
}
if (viewHolder is not THolder holder)
{
throw new InvalidOperationException(
$"RecyclerView item render '{GetType().FullName}' expects holder '{typeof(THolder).FullName}', but got '{viewHolder.GetType().FullName}'.");
}
ResetState();
Holder = holder;
OnHolderChanged();
}
private void EnsureHolder()
{
if (Holder == null)
{
throw new InvalidOperationException(
$"RecyclerView item render '{GetType().FullName}' has not been initialized with a holder.");
}
}
private void ResetState()
{
if (Holder != null)
{
if (IsSelected)
{
IsSelected = false;
OnSelectionChanged(false);
}
OnClear();
Holder.ClearInteractionCallbacks();
}
CurrentData = default;
CurrentIndex = -1;
IsSelected = false;
defaultClickAction = null;
}
}
internal static class ItemRenderResolver
{
internal sealed class ItemRenderDefinition
{
private readonly ConstructorInfo constructor;
public ItemRenderDefinition(Type itemRenderType, Type holderType, ConstructorInfo constructor)
public ItemRenderDefinition(Type itemRenderType, Type holderType)
{
ItemRenderType = itemRenderType;
HolderType = holderType;
this.constructor = constructor;
}
public Type ItemRenderType { get; }
@ -128,7 +177,20 @@ namespace AlicizaX.UI
$"RecyclerView item render '{ItemRenderType.FullName}' expects holder '{HolderType.FullName}', but got '{viewHolder.GetType().FullName}'.");
}
return (IItemRender)constructor.Invoke(new object[] { viewHolder });
if (Activator.CreateInstance(ItemRenderType, true) is not IItemRender itemRender)
{
throw new InvalidOperationException(
$"RecyclerView item render '{ItemRenderType.FullName}' could not be created.");
}
if (itemRender is not IItemRenderInitializer initializer)
{
throw new InvalidOperationException(
$"RecyclerView item render '{ItemRenderType.FullName}' must inherit from ItemRender<TData, THolder>.");
}
initializer.Reset(viewHolder);
return itemRender;
}
}
@ -171,16 +233,16 @@ namespace AlicizaX.UI
ConstructorInfo constructor = itemRenderType.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new[] { holderType },
Type.EmptyTypes,
null);
if (constructor == null)
{
throw new InvalidOperationException(
$"RecyclerView item render '{itemRenderType.FullName}' must declare a constructor with a single '{holderType.FullName}' parameter.");
$"RecyclerView item render '{itemRenderType.FullName}' must have a parameterless constructor.");
}
return new ItemRenderDefinition(itemRenderType, holderType, constructor);
return new ItemRenderDefinition(itemRenderType, holderType);
}
private static bool TryGetHolderType(Type itemRenderType, out Type holderType)