一、发现需求
1、在UGUI中,使用 ScrollView + 表格布局和字段自适应组件 就可以很好的实现列表功能。
2、如果列表中同时存在很多个Item时,显示区域却只显示一部分,就会造成性能不必要的浪费。
3、这时就想到,利用对象池相关知识,只在列表显示的地方实例化有限的Item即可。
二、实现原理
在列表滑动时,根据Content移动的位置偏差,计算出当前需要显示的Item索引,配合对象池,动态刷新Item数据。
三、实现需求
1、新建一个ScrollView,给物体添加CircularScrollRect脚本,设置好参数。
2、然后在其他脚本在合适的时机调用 CircularScrollRect 的 Init()、ShowAndUpdateList()、ClearScrollRectAllItem()等方法即可。
最终效果:
使用【customeditor特性】给CircularScrollRect脚本写了一个编辑器拓展,方便调参.
部分代码:
/// <summary>
/// 滑动content,更新Item.
/// </summary>
private void UpdateCheck()
{
if (m_ItemInfos == null) return; //没有Item,不执行.
//检查超出范围
for (int i = 0, length = m_ItemInfos.Length; i < length; i++)
{
ItemInfo itemInfo = m_ItemInfos[i];
GameObject obj = itemInfo.obj;
Vector3 pos = itemInfo.pos;
float posXY = m_Direction == ScrollRect_Direction.Vertical ? pos.y : pos.x;
if (IsOutRange(posXY)) //超出显示范围.
{
//把超出范围的item 扔进 poolsObj里.
if (obj != null)
{
EnterPoolsObj(obj);
m_ItemInfos[i].obj = null;
}
}
else //在显示范围内.
{
//已在范围内的Item,不需要设置.
if (obj == null)
{
GameObject item = GetPoolsObj(); //优先从 poolsObj中 取出. (poolsObj为空则返回 实例化的item)
item.transform.localPosition = pos;
item.gameObject.name = m_ItemName + "_" + i.ToString();
m_ItemInfos[i].obj = item;
ImplementActionMethod(m_itemUpdateCallBack, item);
}
}
}
}
/// <summary>
/// 判断是否超出显示范围.
/// </summary>
/// <param name="posXY">垂直为Y,水平为X</param>
/// <returns></returns>
private bool IsOutRange(float posXY)
{
Vector3 contentPos = m_Content_RTrans.anchoredPosition;
#region if Item中心点在左上角.
if (m_ItemPivot == Item_Pivot.LeftUp) //Item中心点在左上角.
{
if (m_Direction == ScrollRect_Direction.Vertical) //垂直方向.
{
if (posXY + contentPos.y > m_ItemObj_Height || //上方超出范围.
posXY + contentPos.y < -m_RTrans.rect.height) //下方超出范围.
{
return true;
}
}
else //水平方向.
{
if (posXY + contentPos.x < -m_ItemObj_Width || //左方超出范围.
posXY + contentPos.x > m_RTrans.rect.width) //右方超出范围.
{
return true;
}
}
return false;
}
#endregion
#region else if Item中心点在中央.
else if (m_ItemPivot == Item_Pivot.Center) //Item中心点在中央.
{
if (m_Direction == ScrollRect_Direction.Vertical) //垂直方向.
{
if (posXY + (m_ItemObj_Height / 2) + contentPos.y > m_ItemObj_Height || //上方超出范围.
posXY + (m_ItemObj_Height / 2) + contentPos.y < -m_RTrans.rect.height) //下方超出范围.
{
return true;
}
}
else //水平方向.
{
if (posXY + (m_ItemObj_Width / 2) + contentPos.x < -m_ItemObj_Width || //左方超出范围.
posXY - (m_ItemObj_Width / 2) + contentPos.x > m_RTrans.rect.width) //右方超出范围.
{
return true;
}
}
return false;
}
#endregion
#region else Item中心点在其他位置.
else //Item中心点在其他位置.Obsolete
{
return true;
}
#endregion
}
这是以前写的代码,当时阅览过不小博客资源,若有雷同,侵删,完毕.