From cddf34948de6c60621719c6e30f4fc8e92e600c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com> Date: Mon, 30 Mar 2026 15:40:00 +0800 Subject: [PATCH] 11 --- Runtime/RecyclerView/Adapter/ItemRender.cs | 106 ++++++++++++++++----- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/Runtime/RecyclerView/Adapter/ItemRender.cs b/Runtime/RecyclerView/Adapter/ItemRender.cs index cb51b97..3ae31d9 100644 --- a/Runtime/RecyclerView/Adapter/ItemRender.cs +++ b/Runtime/RecyclerView/Adapter/ItemRender.cs @@ -13,25 +13,28 @@ namespace AlicizaX.UI void Unbind(); } + internal interface IItemRenderInitializer + { + void Reset(ViewHolder viewHolder); + } + public abstract class ItemRender : 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."); + } + + 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)