using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using YIUIFramework;
namespace ET.Client
{
///
/// 无限循环列表 (异步)
/// 文档: https://lib9kmxvq7k.feishu.cn/wiki/HPbwwkhsKi9aDik5VEXcqPhDnIh
///
[FriendOf(typeof(YIUILoopScrollChild))]
[EntitySystemOf(typeof(YIUILoopScrollChild))]
public static partial class YIUILoopScrollChildSystem
{
#region ObjectSystem
[EntitySystem]
private static void Awake(this YIUILoopScrollChild self)
{
self.m_OwnerEntity = self.GetParent();
self.AwakePreLoad();
}
[EntitySystem]
private static void Awake(this YIUILoopScrollChild self, LoopScrollRect owner, Type itemType)
{
self.m_OwnerEntity = self.GetParent();
self.Initialize(owner, itemType);
self.AwakePreLoad();
}
[EntitySystem]
private static void Awake(this YIUILoopScrollChild self, LoopScrollRect owner, Type itemType, string itemClickEventName)
{
self.m_OwnerEntity = self.GetParent();
self.Initialize(owner, itemType);
self.SetOnClick(itemClickEventName);
self.AwakePreLoad();
}
[EntitySystem]
private static void Destroy(this YIUILoopScrollChild self)
{
self.m_ItemPool?.Clear((obj) => { ((Entity)obj)?.Parent?.Dispose(); });
foreach (var code in self.m_BanLayerOptionForeverHashSet)
{
self.YIUIMgr()?.RecoverLayerOptionForever(code);
}
}
#endregion
#region Private
public static void Initialize(this YIUILoopScrollChild self, LoopScrollRect owner, Type itemType)
{
var data = self.YIUIBind().GetBindVoByType(itemType);
if (data == null) return;
self.m_Owner = owner;
self.m_ItemType = itemType;
self.m_ItemTransformDic.Clear();
self.m_ItemTransformIndexDic.Clear();
self.m_BindVo = data.Value;
self.m_ItemPool = new(self, self.OnCreateItemRenderer);
self.m_Owner.prefabSource = self;
self.m_Owner.dataSource = self;
self.InitClearContent();
self.InitCacheParent();
self.m_InvokeLoadInstantiate = new YIUIInvokeEntity_LoadInstantiateByVo
{
BindVo = self.m_BindVo,
ParentEntity = self,
ParentTransform = self.CacheRect,
};
}
private static void InitCacheParent(this YIUILoopScrollChild self)
{
if (self.m_Owner.u_CacheRect != null)
{
self.m_Owner.u_CacheRect.gameObject.SetActive(false);
}
else
{
var cacheObj = new GameObject("Cache");
var cacheRect = cacheObj.GetOrAddComponent();
self.m_Owner.u_CacheRect = cacheRect;
cacheRect.SetParent(self.m_Owner.transform, false);
cacheObj.SetActive(false);
}
}
//不应该初始化时有内容 所有不管是什么全部摧毁
private static void InitClearContent(this YIUILoopScrollChild self)
{
var count = self.Content.childCount;
for (var i = 0; i < count; i++)
{
var child = self.Content.GetChild(0);
child.gameObject.SafeDestroySelf();
}
}
private static Entity GetItemRendererByDic(this YIUILoopScrollChild self, Transform tsf)
{
if (self.m_ItemTransformDic.TryGetValue(tsf, out EntityRef value))
{
return value;
}
Debug.LogError($"{tsf.name} 没找到这个关联对象 请检查错误");
return null;
}
private static void AddItemRendererByDic(this YIUILoopScrollChild self, Transform tsf, Entity item)
{
self.m_ItemTransformDic.TryAdd(tsf, item);
}
private static int GetItemIndex(this YIUILoopScrollChild self, Transform tsf)
{
return self.m_ItemTransformIndexDic.GetValueOrDefault(tsf, -1);
}
private static void ResetItemIndex(this YIUILoopScrollChild self, Transform tsf, int index)
{
self.m_ItemTransformIndexDic[tsf] = index;
}
#endregion
#region LoopScrollRect Interface
private static async ETTask> OnCreateItemRenderer(this YIUILoopScrollChild self)
{
EntityRef selfRef = self;
var item = await EventSystem.Instance?.YIUIInvokeEntityAsync>(self, self.m_InvokeLoadInstantiate);
self = selfRef;
if (item == null)
{
Log.Error($"YIUILoopScroll 实例化失败 请检查 {self.m_BindVo.PkgName} {self.m_BindVo.ResName}");
return null;
}
var ownerRectTransform = item.GetParent().OwnerRectTransform;
#if UNITY_EDITOR
if (!self.m_FirstCheckLayoutElement)
{
var layoutElement = ownerRectTransform.GetComponent();
if (layoutElement == null)
{
var layoutGroup = ownerRectTransform.GetComponent();
if (layoutGroup == null)
{
Debug.LogError($"{ownerRectTransform.name} 没有LayoutElement组件 请检查错误");
}
}
self.m_FirstCheckLayoutElement = true;
}
#endif
self.AddItemRendererByDic(ownerRectTransform, item);
self.AddOnClickEvent(item);
return item;
}
private static async ETTask GetObject(this YIUILoopScrollChild self, int index)
{
var item = await self.m_ItemPool.Get();
return ((Entity)item)?.GetParent()?.OwnerGameObject;
}
private static void ReturnObject(this YIUILoopScrollChild self, Transform transform)
{
var item = self.GetItemRendererByDic(transform);
if (item == null) return;
self.m_ItemPool.Put(item);
self.ResetItemIndex(transform, -1);
transform.SetParent(self.m_Owner.u_CacheRect, false);
}
//初始化后预加载指定数量的实例
//适用于部分情况下需要提前加载实例 减少卡顿
//但是你本来就是打开后马上就刷新列表 那就没必要预加载了
private static void AwakePreLoad(this YIUILoopScrollChild self)
{
if (self.PreLoadCount <= 0) return;
self.PreLoadAsync(self.PreLoadCount).NoContext();
}
public static async ETTask PreLoadAsync(this YIUILoopScrollChild self, int count)
{
EntityRef selfRef = self;
using var coroutineLock = await self.Root().GetComponent().Wait(CoroutineLockType.YIUIFramework, self.GetHashCode());
self = selfRef;
var loadCount = count - self.m_ItemPool.Count;
if (loadCount <= 0) return;
using var listTemp = ListComponent>.Create();
for (var i = 0; i < loadCount; i++)
{
self = selfRef;
var item = await self.m_ItemPool.Get();
var transform = ((Entity)item)?.GetParent()?.OwnerRectTransform;
if (transform != null)
{
self = selfRef;
transform.SetParent(self.m_Owner.u_CacheRect, false);
listTemp.Add(item);
}
}
foreach (var item in listTemp)
{
self.m_ItemPool.Put(item);
}
}
private static void ProvideData(this YIUILoopScrollChild self, Transform transform, int index)
{
var item = self.GetItemRendererByDic(transform);
if (item == null) return;
self.ResetItemIndex(transform, index);
var select = self.m_OnClickItemHashSet.Contains(index);
if (self.Data == null)
{
Debug.LogError($"{self.Parent.GetType().Name} {self.m_Owner.name}当前没有设定数据 m_Data == null");
return;
}
YIUILoopHelper.Renderer(self.m_LoopRendererSystemType, self.OwnerEntity, item, self.Data[index], index, select);
}
//原地刷新 重新触发一次可见的Item 时候数据变化 但是长度不变
//又不想全刷新也不想改变当前滑动位置,选中状态等等, 纯只刷新状态用
private static void UpdateRenderer(this YIUILoopScrollChild self, int index)
{
var item = self.GetItemByIndex(index);
if (item == null)
{
Debug.LogError($"没有找到 {index} 对应的item");
return;
}
var select = self.m_OnClickItemHashSet.Contains(index);
if (self.Data == null)
{
Debug.LogError($"{self.Parent.GetType().Name} {self.m_Owner.name}当前没有设定数据 m_Data == null");
return;
}
YIUILoopHelper.Renderer(self.m_LoopRendererSystemType, self.OwnerEntity, item, self.Data[index], index, select);
}
#endregion
#region EntitySystem
[EntitySystem]
public class YIUILoopScrollPrefabAsyncSource : YIUILoopScrollPrefabAsyncSourceSystem
{
protected override async ETTask GetObject(YIUILoopScrollChild self, int index)
{
return await self.GetObject(index);
}
protected override void ReturnObject(YIUILoopScrollChild self, Transform trans)
{
self.ReturnObject(trans);
}
}
[EntitySystem]
public class YIUILoopScrollDataSource : YIUILoopScrollDataSourceSystem
{
protected override void ProvideData(YIUILoopScrollChild self, Transform transform, int idx)
{
self.ProvideData(transform, idx);
}
}
#endregion
}
}