首先看一下效果
主要功能如下:
1.可以初始化任意长度
2.可以移动到任意一个index中
3.可以动态移除当前列表的某一项数据
4.可以动态增添数据
下面会附上工程和代码
https://download.csdn.net/download/ldy597321444/10357647
LoopListExample
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LoopListExample : MonoBehaviour
{
public DynamicInfinityListRenderer m_Dl;
public Button m_BtnSetDatas;
public Button m_BtnMove2Data;
public Button m_BtnRemoveData;
public Button m_BtnAddData;
public int all_Number;
public int moveIndex;
public int removeIndex;
public int addNumber;
// Use this for initialization
void Start () {
m_Dl.InitRendererList(OnSelectHandler,null);
m_BtnSetDatas.onClick.AddListener(() =>
{
List datas = new List();
for (int i = 0; i < all_Number; ++i)
{
datas.Add(i);
}
m_Dl.SetDataProvider(datas);
});
m_BtnMove2Data.onClick.AddListener(() =>
{
if (m_Dl.GetDataProvider() != null)
{
m_Dl.LocateRenderItemAtTarget(moveIndex, 1);
}
else
{
print("先设置数据吧");
}
});
m_BtnRemoveData.onClick.AddListener(() =>
{
if (m_Dl.GetDataProvider() != null)
{
if (m_Dl.GetDataProvider().Contains(removeIndex))
{
m_Dl.GetDataProvider().Remove(removeIndex);
m_Dl.RefreshDataProvider();
}
else
{
print("找不到数据");
}
}
else
{
print("先设置数据吧");
}
});
m_BtnAddData.onClick.AddListener(() =>
{
if (m_Dl.GetDataProvider() != null)
{
m_Dl.GetDataProvider().Add(addNumber);
m_Dl.RefreshDataProvider();
}
else
{
print("先设置数据吧");
}
});
}
void OnSelectHandler(DynamicInfinityItem item)
{
print("on select "+item.ToString());
}
// Update is called once per frame
void Update () {
}
}
DynamicInfinityListRenderer
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 动态无限列表
/// @panhaijie
/// 2016年3月22日 10:27:51
///
public class DynamicInfinityListRenderer : MonoBehaviour
{
///
/// 单元格尺寸(宽,高)
///
public Vector2 CellSize;
///
/// 单元格间隙(水平,垂直)
///
public Vector2 SpacingSize;
///
/// 列数
///
public int ColumnCount;
///
/// 单元格渲染器prefab
///
public GameObject RenderGO;
///
/// 渲染格子数
///
protected int mRendererCount;
///
/// 父节点蒙版尺寸
///
private Vector2 mMaskSize;
///
/// 蒙版矩形
///
private Rect mRectMask;
protected ScrollRect mScrollRect;
///
/// 转换器
///
protected RectTransform mRectTransformContainer;
///
/// 渲染脚本集合
///
protected List mList_items;
///
/// 渲染格子字典
///
private Dictionary mDict_dRect;
///
/// 数据提供者
///
protected IList mDataProviders;
protected bool mHasInited = false;
///
/// 初始化渲染脚本
///
public virtual void InitRendererList(DynamicInfinityItem.OnSelect OnSelect, DynamicInfinityItem.OnUpdateData OnUpdate)
{
if (mHasInited) return;
//转换器
mRectTransformContainer = transform as RectTransform;
//获得蒙版尺寸
mMaskSize = transform.parent.GetComponent().sizeDelta;
mScrollRect = transform.parent.GetComponent();
//通过蒙版尺寸和格子尺寸计算需要的渲染器个数
mRendererCount = ColumnCount * (Mathf.CeilToInt(mMaskSize.y / GetBlockSizeY()) + 1);
_UpdateDynmicRects(mRendererCount);
mList_items = new List();
for (int i = 0; i < mRendererCount; ++i)
{
GameObject child = GameObject.Instantiate(RenderGO);
child.transform.SetParent(transform);
child.transform.localRotation = Quaternion.identity;
child.transform.localScale = Vector3.one;
child.layer = gameObject.layer;
DynamicInfinityItem dfItem = child.GetComponent();
if (dfItem == null)
throw new Exception("Render must extend DynamicInfinityItem");
mList_items.Add(dfItem);
mList_items[i].DRect = mDict_dRect[i];
mList_items[i].OnSelectHandler = OnSelect;
mList_items[i].OnUpdateDataHandler = OnUpdate;
child.SetActive(false);
_UpdateChildTransformPos(child, i);
}
_SetListRenderSize(mRendererCount);
mHasInited = true;
}
///
/// 设置渲染列表的尺寸
/// 不需要public
///
///
void _SetListRenderSize(int count)
{
mRectTransformContainer.sizeDelta = new Vector2(mRectTransformContainer.sizeDelta.x, Mathf.CeilToInt((count * 1.0f / ColumnCount)) * GetBlockSizeY());
mRectMask = new Rect(0, -mMaskSize.y, mMaskSize.x, mMaskSize.y);
mScrollRect.vertical = mRectTransformContainer.sizeDelta.y > mMaskSize.y;
}
///
/// 更新各个渲染格子的位置
///
///
///
void _UpdateChildTransformPos(GameObject child, int index)
{
int row = index / ColumnCount;
int column = index % ColumnCount;
Vector2 v2Pos = new Vector2();
v2Pos.x = column * GetBlockSizeX();
v2Pos.y = -CellSize.y - row * GetBlockSizeY();
((RectTransform)child.transform).anchoredPosition3D = Vector3.zero;
((RectTransform)child.transform).anchoredPosition = v2Pos;
}
///
/// 获得格子块尺寸
///
///
protected float GetBlockSizeY() { return CellSize.y + SpacingSize.y; }
protected float GetBlockSizeX() { return CellSize.x + SpacingSize.x; }
///
/// 更新动态渲染格
/// 不需要public
///
///
void _UpdateDynmicRects(int count)
{
mDict_dRect = new Dictionary();
for (int i = 0; i < count; ++i)
{
int row = i / ColumnCount;
int column = i % ColumnCount;
DynamicRect dRect = new DynamicRect(column * GetBlockSizeX(), -row * GetBlockSizeY() - CellSize.y, CellSize.x, CellSize.y, i);
mDict_dRect[i] = dRect;
}
}
///
/// 设置数据提供者
///
///
public void SetDataProvider(IList datas)
{
_UpdateDynmicRects(datas.Count);
_SetListRenderSize(datas.Count);
mDataProviders = datas;
ClearAllListRenderDr();
}
///
/// 清理可复用渲染格
/// 不需要public
///
void ClearAllListRenderDr()
{
if (mList_items != null)
{
int len = mList_items.Count;
for (int i = 0; i < len; ++i)
{
DynamicInfinityItem item = mList_items[i];
item.DRect = null;
}
}
}
///
/// 获得数据提供者
///
///
public IList GetDataProvider() { return mDataProviders; }
///
/// 数据发生变化 供外部调用刷新列表
///
[ContextMenu("RefreshDataProvider")]
public void RefreshDataProvider()
{
if (mDataProviders == null)
throw new Exception("dataProviders 为空!请先使用SetDataProvider ");
_UpdateDynmicRects(mDataProviders.Count);
_SetListRenderSize(mDataProviders.Count);
ClearAllListRenderDr();
}
#region 移动至数据
///
/// 移动列表使之能定位到给定数据的位置上
///
///
public virtual void LocateRenderItemAtTarget(object target, float delay)
{
LocateRenderItemAtIndex(mDataProviders.IndexOf(target), delay);
}
public virtual void LocateRenderItemAtIndex(int index, float delay)
{
if (index < 0 || index > mDataProviders.Count - 1)
throw new Exception("Locate Index Error " + index);
index = Math.Min(index, mDataProviders.Count - mRendererCount + 2);
index = Math.Max(0, index);
Vector2 pos = mRectTransformContainer.anchoredPosition;
int row = index / ColumnCount;
Vector2 v2Pos = new Vector2(pos.x, row * GetBlockSizeY());
m_Coroutine = StartCoroutine(TweenMoveToPos(pos, v2Pos, delay));
}
protected IEnumerator TweenMoveToPos(Vector2 pos, Vector2 v2Pos, float delay)
{
bool running = true;
float passedTime = 0f;
while (running)
{
yield return new WaitForEndOfFrame();
passedTime += Time.deltaTime;
Vector2 vCur;
if (passedTime >= delay)
{
vCur = v2Pos;
running = false;
StopCoroutine(m_Coroutine);
m_Coroutine = null;
}
else
{
vCur = Vector2.Lerp(pos, v2Pos, passedTime / delay);
}
mRectTransformContainer.anchoredPosition = vCur;
}
}
protected Coroutine m_Coroutine = null;
#endregion
protected void UpdateRender()
{
mRectMask.y = -mMaskSize.y - mRectTransformContainer.anchoredPosition.y;
Dictionary inOverlaps = new Dictionary();
foreach (DynamicRect dR in mDict_dRect.Values)
{
if (dR.Overlaps(mRectMask))
{
inOverlaps.Add(dR.Index, dR);
}
}
int len = mList_items.Count;
for (int i = 0; i < len; ++i)
{
DynamicInfinityItem item = mList_items[i];
if (item.DRect != null && !inOverlaps.ContainsKey(item.DRect.Index))
item.DRect = null;
}
foreach (DynamicRect dR in inOverlaps.Values)
{
if (GetDynmicItem(dR) == null)
{
DynamicInfinityItem item = GetNullDynmicItem();
item.DRect = dR;
_UpdateChildTransformPos(item.gameObject, dR.Index);
if (mDataProviders != null && dR.Index < mDataProviders.Count)
{
item.SetData(mDataProviders[dR.Index]);
}
}
}
}
///
/// 获得待渲染的渲染器
///
///
DynamicInfinityItem GetNullDynmicItem()
{
int len = mList_items.Count;
for(int i=0;i< len;++i)
{
DynamicInfinityItem item = mList_items[i];
if (item.DRect == null)
return item;
}
throw new Exception("Error");
}
///
/// 通过动态格子获得动态渲染器
///
///
///
DynamicInfinityItem GetDynmicItem(DynamicRect rect)
{
int len = mList_items.Count;
for (int i = 0; i < len; ++i)
{
DynamicInfinityItem item = mList_items[i];
if (item.DRect == null)
continue;
if (rect.Index == item.DRect.Index)
return item;
}
return null;
}
void Update()
{
if (mHasInited)
UpdateRender();
}
}
DynamicRect
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
///
/// 动态格子矩形
///
public class DynamicRect
{
///
/// 矩形数据
///
private Rect mRect;
///
/// 格子索引
///
public int Index;
public DynamicRect(float x, float y, float width, float height, int index)
{
this.Index = index;
mRect = new Rect(x, y, width, height);
}
///
/// 是否相交
///
///
///
public bool Overlaps(DynamicRect otherRect)
{
return mRect.Overlaps(otherRect.mRect);
}
///
/// 是否相交
///
///
///
public bool Overlaps(Rect otherRect)
{
return mRect.Overlaps(otherRect);
}
public override string ToString()
{
return string.Format("index:{0},x:{1},y:{2},w:{3},h:{4}", Index, mRect.x, mRect.y, mRect.width, mRect.height);
}
}
///
/// 动态无限渲染器
/// @panhaijie
///
public class DynamicInfinityItem : MonoBehaviour
{
public delegate void OnSelect(DynamicInfinityItem item);
public delegate void OnUpdateData(DynamicInfinityItem item);
public OnSelect OnSelectHandler;
public OnUpdateData OnUpdateDataHandler;
///
/// 动态矩形
///
protected DynamicRect mDRect;
///
/// 动态格子数据
///
protected object mData;
public DynamicRect DRect
{
set
{
mDRect = value;
gameObject.SetActive(value != null);
}
get { return mDRect; }
}
void Start()
{
}
///
/// 设置数据
///
///
public void SetData(object data)
{
if (data == null)
{
return;
}
mData = data;
if (null != OnUpdateDataHandler)
OnUpdateDataHandler(this);
OnRenderer();
}
///
/// 复写
///
protected virtual void OnRenderer()
{
}
///
/// 返回数据
///
///
public object GetData()
{
return mData;
}
public T GetData()
{
return (T)mData;
}
}
ItemRender
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class ItemRender : DynamicInfinityItem
{
public Text m_TxtName;
public Button m_Btn;
// Use this for initialization
void Start () {
m_Btn.onClick.AddListener(() =>
{
print("Click "+mData.ToString());
});
}
protected override void OnRenderer()
{
base.OnRenderer();
m_TxtName.text = mData.ToString();
}
}