using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
///
/// 滚动列表优化
///
[DisallowMultipleComponent]
public class UIWarpContent : MonoBehaviour
{
///
/// 元素初始化
///
/// 游戏对象
/// 数据索引
public delegate void OnInitializeItem(GameObject go, int dataIndex);
///
/// 元素初始化
///
public OnInitializeItem onInitializeItem;
///
/// 排列
///
public enum Arrangement
{
///
/// 横
///
Horizontal,
///
/// 竖
///
Vertical,
}
///
/// 排列
///
public Arrangement arrangement = Arrangement.Horizontal;
///
/// Maximum children per line.
/// If the arrangement is horizontal, this denotes the number of columns.
/// If the arrangement is vertical, this stands for the number of rows.
///
[Range(1, 50)]
public int maxPerLine = 1;
///
/// The width of each of the cells.
///
public float cellWidth = 200f;
///
/// The height of each of the cells.
///
public float cellHeight = 200f;
///
/// The Width Space of each of the cells.
///
[Range(0, 50)]
public float cellWidthSpace = 0f;
///
/// The Height Space of each of the cells.
///
[Range(0, 50)]
public float cellHeightSpace = 0f;
///
/// 窗口能容纳的 行数 或 列数
///
[Range(0, 30)]
public int viewCount = 5;
///
/// scroll view 对象
///
public ScrollRect scrollRect = null;
///
/// content 对象
///
public RectTransform content = null;
///
/// 元素预制物体
///
public GameObject goItemPrefab = null;
///
/// 数据的数量
///
private int mDataCount = 0;
///
/// 当前所处的行数
///
private int curScrollPerLineIndex = -1;
///
/// 正在使用中的元素
///
private List listItem = new List();
///
/// 未在使用中的元素
///
private Queue unUseItem = new Queue();
///
/// 初始化
///
private void Awake()
{
}
///
/// 初始化
///
/// 数据的数量
public void Init(int dataCount)
{
if (scrollRect == null || content == null || goItemPrefab == null)
{
Debug.LogError("异常:请检测<" + gameObject.name + ">对象上UIWarpContent对应ScrollRect、Content、GoItemPrefab 是否存在值...." + scrollRect + " _" + content + "_" + goItemPrefab);
return;
}
// 不显示元素预制物体
goItemPrefab.SetActive(false);
scrollRect.onValueChanged.RemoveAllListeners();
scrollRect.onValueChanged.AddListener(onValueChanged);
// 如果数据数量为 0 ,没有初始化的必要
if (dataCount <= 0)
{
return;
}
// 设置数据的数量,并计算 content 的尺寸
setDataCount(dataCount);
unUseItem.Clear();
listItem.Clear();
setUpdateRectItem(0);
}
///
/// 数据改变了,比如切换分类功能,全部,前排,中排,后排,元素要重新获取数据
///
/// 数据的数量
/// 是否返回初始位置
public void DataChange(int dataCount, bool bResetPos)
{
if (scrollRect == null || content == null || goItemPrefab == null)
{
Debug.LogError("异常:请检测<" + gameObject.name + ">对象上UIWarpContent对应ScrollRect、Content、GoItemPrefab 是否存在值...." + scrollRect + " _" + content + "_" + goItemPrefab);
return;
}
// 重新设置数量,重新计算 content 的尺寸
setDataCount(dataCount);
// 因为数据改变了,元素要重新获取数据
for (int i = listItem.Count - 1; i >= 0; i--)
{
UIWarpContentItem item = listItem[i];
item.Index = -1;
listItem.Remove(item);
unUseItem.Enqueue(item);
}
if (bResetPos)
{
content.anchoredPosition = Vector3.zero;
}
// 计算当前所处的行数,刷新
int _curScrollPerLineIndex = getCurScrollPerLineIndex();
setUpdateRectItem(_curScrollPerLineIndex);
}
///
/// 设置数据的数量,并重新计算 content 的尺寸
///
/// 数据的数量
private void setDataCount(int count)
{
if (mDataCount == count)
{
return;
}
mDataCount = count;
// 计算 content 的尺寸
setUpdateContentSize();
}
///
/// scroll view 拖动时触发
///
/// 拖动数值
private void onValueChanged(Vector2 vt2)
{
int _curScrollPerLineIndex = getCurScrollPerLineIndex();
if (_curScrollPerLineIndex == curScrollPerLineIndex)
{
return;
}
setUpdateRectItem(_curScrollPerLineIndex);
}
///
/// 刷新元素
///
/// 当前所处的行数
private void setUpdateRectItem(int scrollPerLineIndex)
{
if (scrollPerLineIndex < 0)
{
return;
}
curScrollPerLineIndex = scrollPerLineIndex;
int startDataIndex = curScrollPerLineIndex * maxPerLine;
int endDataIndex = (curScrollPerLineIndex + viewCount) * maxPerLine;
// 移除
for (int i = listItem.Count - 1; i >= 0; i--)
{
UIWarpContentItem item = listItem[i];
int index = item.Index;
if (index < startDataIndex || index >= endDataIndex)
{
item.Index = -1;
listItem.Remove(item);
unUseItem.Enqueue(item);
}
}
// 显示
for (int dataIndex = startDataIndex; dataIndex < endDataIndex; dataIndex++)
{
if (dataIndex >= mDataCount)
{
continue;
}
if (isExistDataByDataIndex(dataIndex))
{
continue;
}
createItem(dataIndex);
}
}
///
/// 添加当前数据索引数据
///
/// 数据索引
public void AddItem(int dataIndex)
{
if (dataIndex < 0 || dataIndex > mDataCount)
{
return;
}
// 检测是否需添加gameObject
bool isNeedAdd = false;
for (int i = listItem.Count - 1; i >= 0; i--)
{
UIWarpContentItem item = listItem[i];
if (item.Index >= (mDataCount - 1))
{
isNeedAdd = true;
break;
}
}
setDataCount(mDataCount + 1);
if (isNeedAdd)
{
for (int i = 0; i < listItem.Count; i++)
{
UIWarpContentItem item = listItem[i];
int oldIndex = item.Index;
if (oldIndex >= dataIndex)
{
item.Index = oldIndex + 1;
}
item = null;
}
setUpdateRectItem(getCurScrollPerLineIndex());
}
else
{
// 重新刷新数据
for (int i = 0; i < listItem.Count; i++)
{
UIWarpContentItem item = listItem[i];
int oldIndex = item.Index;
if (oldIndex >= dataIndex)
{
item.Index = oldIndex;
}
item = null;
}
}
}
///
/// 删除当前数据索引下数据
///
/// 数据索引
public void DelItem(int dataIndex)
{
if (dataIndex < 0 || dataIndex >= mDataCount)
{
return;
}
////删除item逻辑三种情况
////1.只更新数据,不销毁gameObject,也不移除gameobject
////2.更新数据,且移除gameObject,不销毁gameObject
////3.更新数据,销毁gameObject
bool isNeedDestroyGameObject = (listItem.Count >= mDataCount);
setDataCount(mDataCount - 1);
for (int i = listItem.Count - 1; i >= 0; i--)
{
UIWarpContentItem item = listItem[i];
int oldIndex = item.Index;
if (oldIndex == dataIndex)
{
listItem.Remove(item);
if (isNeedDestroyGameObject)
{
GameObject.Destroy(item.gameObject);
}
else
{
item.Index = -1;
unUseItem.Enqueue(item);
}
}
if (oldIndex > dataIndex)
{
item.Index = oldIndex - 1;
}
}
setUpdateRectItem(getCurScrollPerLineIndex());
}
///
/// 根据数据索引计算在 content 下的 local position
///
/// 数据索引
/// 位置
public Vector3 getLocalPositionByIndex(int index)
{
if (index < 0)
{
return new Vector3(-2000.0f, 2000.0f, 0.0f);
}
float x = 0f;
float y = 0f;
float z = 0f;
switch (arrangement)
{
// 水平方向
case Arrangement.Horizontal:
{
x = (index / maxPerLine) * (cellWidth + cellWidthSpace);
y = -(index % maxPerLine) * (cellHeight + cellHeightSpace);
}
break;
// 垂着方向
case Arrangement.Vertical:
{
x = (index % maxPerLine) * (cellWidth + cellWidthSpace);
y = -(index / maxPerLine) * (cellHeight + cellHeightSpace);
}
break;
default:
{
// 不需要处理
}
break;
}
return new Vector3(x, y, z);
}
///
/// 创建元素
///
/// 数据索引
private void createItem(int dataIndex)
{
UIWarpContentItem item = null;
if (unUseItem.Count > 0)
{
item = unUseItem.Dequeue();
}
else
{
GameObject temp = addChild(goItemPrefab, content);
item = temp.GetComponent();
if (item == null)
{
AssemblyHelper.Instance.BindScript("UIWarpContentItem", temp);
item = temp.GetComponent();
}
}
item.WarpContent = this;
item.Index = dataIndex;
listItem.Add(item);
}
///
/// 当前数据是否存在 List 中
///
/// 数据索引
/// 是否已存在
private bool isExistDataByDataIndex(int dataIndex)
{
if (listItem == null || listItem.Count <= 0)
{
return false;
}
for (int i = 0; i < listItem.Count; i++)
{
if (listItem[i].Index == dataIndex)
{
return true;
}
}
return false;
}
///
/// 根据Content偏移,计算当前开始显示所在数据列表中的行或列
///
/// 行数 或 列数
private int getCurScrollPerLineIndex()
{
int result = 0;
switch (arrangement)
{
// 水平方向
case Arrangement.Horizontal:
{
result = Mathf.FloorToInt(-(content.anchoredPosition.x) / (cellWidth + cellWidthSpace));
}
break;
// 垂着方向
case Arrangement.Vertical:
{
result = Mathf.FloorToInt((content.anchoredPosition.y) / (cellHeight + cellHeightSpace));
}
break;
default:
{
// 不需要处理
}
break;
}
if (result < 0)
{
result = 0;
}
return result;
}
///
/// 计算 content 的尺寸
///
private void setUpdateContentSize()
{
// 行数,向上取整
int lineCount = Mathf.CeilToInt((float)mDataCount / maxPerLine);
switch (arrangement)
{
case Arrangement.Horizontal:
{
content.sizeDelta = new Vector2((cellWidth * lineCount) + (cellWidthSpace * (lineCount - 1)), content.sizeDelta.y);
}
break;
case Arrangement.Vertical:
{
content.sizeDelta = new Vector2(content.sizeDelta.x, (cellHeight * lineCount) + (cellHeightSpace * (lineCount - 1)));
}
break;
default:
{
// 不需要处理
}
break;
}
}
///
/// 实例化预设对象 、添加实例化对象到指定的子对象下
///
/// 元素预制物体
/// 父节点
/// 新创建的元素对象
private GameObject addChild(GameObject goPrefab, Transform parent)
{
if (goPrefab == null || parent == null)
{
Debug.LogError("异常。UIWarpContent.cs addChild(goPrefab = null || parent = null)");
return null;
}
GameObject goChild = GameObject.Instantiate(goPrefab) as GameObject;
goChild.transform.SetParent(parent, false);
goChild.SetActive(true);
return goChild;
}
///
/// 销毁
///
private void OnDestroy()
{
scrollRect = null;
content = null;
goItemPrefab = null;
onInitializeItem = null;
listItem.Clear();
unUseItem.Clear();
listItem = null;
unUseItem = null;
}
public void SetContentToEnd()
{
float x = 0, y = 0;
RectTransform temp = scrollRect.GetComponent();
if (scrollRect.content.sizeDelta.x > temp.sizeDelta.x)
{
x = scrollRect.content.sizeDelta.x - temp.sizeDelta.x;
}
if (scrollRect.content.sizeDelta.y > temp.sizeDelta.y)
{
y = scrollRect.content.sizeDelta.y - temp.sizeDelta.y;
}
switch (arrangement)
{
case Arrangement.Horizontal:
{
y = 0;
}
break;
case Arrangement.Vertical:
{
x = 0;
}
break;
}
Debug.LogError("end::" + x + " " + y);
scrollRect.content.anchoredPosition = new Vector2(x, y);
}
}