11
This commit is contained in:
parent
40080636d8
commit
cddf34948d
@ -13,25 +13,28 @@ namespace AlicizaX.UI
|
|||||||
void Unbind();
|
void Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal interface IItemRenderInitializer
|
||||||
|
{
|
||||||
|
void Reset(ViewHolder viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class ItemRender<TData, THolder> : IItemRender
|
public abstract class ItemRender<TData, THolder> : IItemRender
|
||||||
|
, IItemRenderInitializer
|
||||||
where THolder : ViewHolder
|
where THolder : ViewHolder
|
||||||
{
|
{
|
||||||
private Action defaultClickAction;
|
private Action defaultClickAction;
|
||||||
|
protected THolder Holder { get; private set; }
|
||||||
protected ItemRender(THolder holder)
|
|
||||||
{
|
|
||||||
Holder = holder ?? throw new ArgumentNullException(nameof(holder));
|
|
||||||
CurrentIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected THolder Holder { get; }
|
|
||||||
|
|
||||||
protected TData CurrentData { 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)
|
public void Bind(object data, int index, Action defaultClickAction)
|
||||||
{
|
{
|
||||||
|
EnsureHolder();
|
||||||
|
|
||||||
if (data is not TData itemData)
|
if (data is not TData itemData)
|
||||||
{
|
{
|
||||||
throw new InvalidCastException(
|
throw new InvalidCastException(
|
||||||
@ -47,20 +50,22 @@ namespace AlicizaX.UI
|
|||||||
|
|
||||||
public void UpdateSelection(bool selected)
|
public void UpdateSelection(bool selected)
|
||||||
{
|
{
|
||||||
|
EnsureHolder();
|
||||||
|
IsSelected = selected;
|
||||||
OnSelectionChanged(selected);
|
OnSelectionChanged(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unbind()
|
public void Unbind()
|
||||||
{
|
{
|
||||||
OnClear();
|
ResetState();
|
||||||
CurrentData = default;
|
|
||||||
CurrentIndex = -1;
|
|
||||||
defaultClickAction = null;
|
|
||||||
Holder.ClearInteractionCallbacks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void Bind(TData data, int index);
|
protected abstract void Bind(TData data, int index);
|
||||||
|
|
||||||
|
protected virtual void OnHolderChanged()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void OnSelectionChanged(bool selected)
|
protected virtual void OnSelectionChanged(bool selected)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -96,19 +101,63 @@ namespace AlicizaX.UI
|
|||||||
{
|
{
|
||||||
OnPointerExit();
|
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 static class ItemRenderResolver
|
||||||
{
|
{
|
||||||
internal sealed class ItemRenderDefinition
|
internal sealed class ItemRenderDefinition
|
||||||
{
|
{
|
||||||
private readonly ConstructorInfo constructor;
|
public ItemRenderDefinition(Type itemRenderType, Type holderType)
|
||||||
|
|
||||||
public ItemRenderDefinition(Type itemRenderType, Type holderType, ConstructorInfo constructor)
|
|
||||||
{
|
{
|
||||||
ItemRenderType = itemRenderType;
|
ItemRenderType = itemRenderType;
|
||||||
HolderType = holderType;
|
HolderType = holderType;
|
||||||
this.constructor = constructor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type ItemRenderType { get; }
|
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}'.");
|
$"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(
|
ConstructorInfo constructor = itemRenderType.GetConstructor(
|
||||||
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
|
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
|
||||||
null,
|
null,
|
||||||
new[] { holderType },
|
Type.EmptyTypes,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
if (constructor == null)
|
if (constructor == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
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)
|
private static bool TryGetHolderType(Type itemRenderType, out Type holderType)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user