using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UILib;
class TableViewGroup
{
public Dictionary<int, RectTransform> visibilityCellQueue = new Dictionary<int, RectTransform>();
public List<RectTransform> invisibilityCellQueue = new List<RectTransform>();
~TableViewGroup()
{
visibilityCellQueue.Clear();
visibilityCellQueue = null;
invisibilityCellQueue.Clear();
invisibilityCellQueue = null;
}
public void QueueInvisible()
{
foreach(int i in visibilityCellQueue.Keys) {
RectTransform trans = visibilityCellQueue[i];
invisibilityCellQueue.Add(trans);
trans.gameObject.SetActive(false);
}
visibilityCellQueue.Clear();
}
}
public class TableView : ScrollRect
{
public const string DEFAULT_IDENTIFIER = "default.identifier";
public delegate int NumberOfCells(TableView tbView);
public delegate float SizeOfIndex(TableView tbView, int index);
public delegate RectTransform TransformOfIndex(TableView tbView, int index);
public delegate string IdentifierOfIndex(TableView tbView, int index);
/// <summary>
/// 返回行数
/// </summary>
public NumberOfCells delegateNumberOfCells = null;
/// <summary>
/// 说明:返回第i行cell的高度(垂直),或宽度(水平)
/// 参数
/// t: TableView
/// i: int 表示第几行
/// </summary>
public SizeOfIndex delegateSizeOfIndex = null;
/// <summary>
/// 说明:返回第i行cell的RectTransform
/// 参数
/// t: TableView
/// i: int 表示第几行
/// </summary>
public TransformOfIndex delegateTransformOfIndex = null;
/// <summary>
/// 说明:返回第i行cell的标识符
/// 参数
/// t: TableView
/// i: int 表示第几行
/// </summary>
public IdentifierOfIndex delegateIdentifierOfIndex = null;
int extraBuffer = 2;
private Rect[] rects;
private Dictionary<string, TableViewGroup> groupDict = new Dictionary<string, TableViewGroup>();
private int numberOfCells = 0;
private int minVisibleIndex = 0;
private int maxVisibleIndex = 0;
protected override void OnDestroy()
{
delegateNumberOfCells = null;
delegateSizeOfIndex = null;
delegateTransformOfIndex = null;
delegateIdentifierOfIndex = null;
base.OnDestroy();
}
protected override void Start()
{
base.Start();
onValueChanged.AddListener(OnMove);
}
bool IsIdentifierExist(string identifier)
{
return groupDict.ContainsKey(identifier + "_v");
}
void OnMove(Vector2 value)
{
//if (horizontal && (value.x < 0 || value.x > 1)) return;
//if (vertical && (value.y < 0 || value.y > 1)) return;
if (numberOfCells == 0) return;
UpdateMinMaxVisibleIndex();
}
private void UpdateMinMaxVisibleIndex()
{
Vector2 minMaxVisibleIndexes = new Vector2(minVisibleIndex, maxVisibleIndex);
Vector2 minMaxIndexes = GetMinMaxVisibleIndex();
int minIndex = (int)minMaxIndexes.x;
int maxIndex = (int)minMaxIndexes.y;
int minAddIndex, maxAddIndex, minRemoveIndex, maxRemoveIndex;
Vector2 intersectRange = minMaxVisibleIndexes.IntersectionRange(minMaxIndexes);
if (intersectRange.y == 0 && minIndex != maxIndex && minIndex != minVisibleIndex && minVisibleIndex != maxVisibleIndex)
{
minAddIndex = minIndex;
maxAddIndex = maxIndex;
minRemoveIndex = minVisibleIndex;
maxRemoveIndex = maxVisibleIndex;
}
else
{
// for remove index
// -------------minV-------------maxV--------
// ------minI----------maxI------------------
if (intersectRange.x == minVisibleIndex)
{
minRemoveIndex = (int)(intersectRange.x + intersectRange.y + 1);
maxRemoveIndex = maxVisibleIndex;
}
else
{
minRemoveIndex = minVisibleIndex;
maxRemoveIndex = (int)(intersectRange.x - 1);
}
// for add index
// -------------minI-------------maxI--------
// ------minV----------maxV------------------
if (intersectRange.x == minIndex)
{
minAddIndex = (int)(intersectRange.x + intersectRange.y + 1);
maxAddIndex = maxIndex;
}
else
{
minAddIndex = minIndex;
maxAddIndex = (int)(intersectRange.x - 1);
}
}
minVisibleIndex = minIndex;
maxVisibleIndex = maxIndex;
for (int i = minRemoveIndex; i <= maxRemoveIndex; i++)
{
RemoveCellAtIndex(i);
}
for (int i = minAddIndex; i <= maxAddIndex; i++)
{
AddCellAtIndex(i);
}
}
private void AddCellAtIndex(int index)
{
if (index >= numberOfCells || index < 0) return;
string identifier = GetIdentifierForIndex(index);
if (groupDict[identifier].visibilityCellQueue.ContainsKey(index) == false)
{
Rect rect = rects[index];
RectTransform trans = delegateTransformOfIndex(this, index);
//trans.anchorMin = new Vector2(0.5f, 0.5f);
//trans.anchorMax = new Vector2(0.5f, 0.5f);
trans.SetParent(content);
//trans.anchoredPosition = new Vector2(rect.x, rect.y);
trans.localRotation = new Quaternion(0, 0, 0, 0);
trans.localScale = Vector3.one;
trans.SetLocalPositionZ(0);
if (vertical)
{
trans.anchoredPosition = new Vector2(rect.x, rect.y - rect.height / 2f);
trans.anchorMin = new Vector2(0f, 1f);
trans.anchorMax = new Vector2(1f, 1f);
trans.pivot = new Vector2(0.5f, 0.5f);
Vector2 v = trans.offsetMin;
v.x = 0;
trans.offsetMin = v;
v = trans.offsetMax;
v.x = 0;
trans.offsetMax = v;
}
else
{
trans.anchoredPosition = new Vector2(rect.x + rect.width / 2f, rect.y);
trans.anchorMin = new Vector2(0f, 0.5f);
trans.anchorMax = new Vector2(0f, 0.5f);
trans.pivot = new Vector2(0.5f, 0.5f);
}
groupDict[identifier].visibilityCellQueue.Add(index, trans);
}
}
private void RemoveCellAtIndex(int index)
{
string identifier = GetIdentifierForIndex(index);
if (groupDict[identifier].visibilityCellQueue.ContainsKey(index) == true)
{
RectTransform trans = groupDict[identifier].visibilityCellQueue[index];
groupDict[identifier].invisibilityCellQueue.Add(trans);
groupDict[identifier].visibilityCellQueue.Remove(index);
trans.gameObject.SetActive(false);
}
}
private int IndexAtOffset(float offset)
{
int minIndex = 0;
int maxIndex = numberOfCells - 1;
maxIndex = maxIndex < 0 ? 0 : maxIndex;
int index = (maxIndex + minIndex) / 2;
if (vertical)
{
while (minIndex < maxIndex)
{
float indexY = rects[index].y;
float nextY = rects[index + 1].y;
if (indexY >= offset && nextY < offset) break;
else if (nextY >= offset) minIndex = index + 1;
else maxIndex = index;
index = (maxIndex + minIndex) / 2;
}
}
else
{
while (minIndex < maxIndex)
{
float indexX = -rects[index].x;
float nextX = -rects[index + 1].x;
if (indexX >= offset && nextX < offset) break;
else if (nextX >= offset) minIndex = index + 1;
else maxIndex = index;
index = (maxIndex + minIndex) / 2;
}
}
return index;
}
private Vector2 GetMinMaxVisibleIndex()
{
RectTransform trans = transform as RectTransform;
Vector2 offset = content.anchoredPosition;
float viewWidth = trans.rect.width;
float viewHeight = trans.rect.height;
int minIndex = vertical ? IndexAtOffset(-offset.y) : IndexAtOffset(offset.x);
int maxIndex = vertical ? IndexAtOffset(-offset.y - viewHeight) : IndexAtOffset(offset.x - viewWidth);
int boundMinIndex = 0;
int boundMaxIndex = numberOfCells - 1;// Mathf.Max(0, numberOfCells - 1);
minIndex = minIndex - extraBuffer / 2;
minIndex = minIndex < boundMinIndex ? boundMinIndex : minIndex;
maxIndex = maxIndex + extraBuffer / 2;
maxIndex = maxIndex > boundMaxIndex ? boundMaxIndex : maxIndex;
return new Vector2(minIndex, maxIndex);
}
/// <summary>
/// 重新加载数据+
/// </summary>
/// <param name="startIndex">重新加载后跳转到第startIndex行,如:10,跳转到第10行。另:-1,跳转到第0行,并执行反弹动画;-2,在当前行刷新</param>
public void ReloadData(int startIndex = 0, bool cleanCell = false)
{
RectTransform trans = transform as RectTransform;
float viewWidth = trans.rect.width;
float viewHeight = trans.rect.height;
if (cleanCell) {
groupDict.Clear();
while (content.childCount > 0)
{
PoolManager.instance.recycle(content.GetChild(0).gameObject);
}
}
else {
foreach(string identifier in groupDict.Keys) {
groupDict[identifier].QueueInvisible();
}
}
numberOfCells = delegateNumberOfCells(this);
rects = new Rect[numberOfCells];
float offsetX = 0f;
float offsetY = 0f;
float width = 0;
float x = 0;
float height = 0;
float y = 0;
Vector2 contentPos = content.anchoredPosition;
Vector2 contentSize = content.sizeDelta;
System.Action<int> createIdentifierGroup = null;
if (delegateIdentifierOfIndex == null)
{
if(groupDict.ContainsKey(DEFAULT_IDENTIFIER) == false) groupDict[DEFAULT_IDENTIFIER] = new TableViewGroup();
}
else
{
createIdentifierGroup = (i) => {
string identifier = delegateIdentifierOfIndex(this, i);
if (groupDict.ContainsKey(identifier) == false) groupDict[identifier] = new TableViewGroup();
};
}
if (vertical)
{
for (int i = 0; i < numberOfCells; i++)
{
height = delegateSizeOfIndex(this, i);
rects[i] = new Rect(0, -y, viewWidth, height);
y += height;
if (i < startIndex) offsetY += height;
if (createIdentifierGroup != null) createIdentifierGroup(i);
}
contentSize.y = y;
}
else
{
for (int i = 0; i < numberOfCells; i++)
{
width = delegateSizeOfIndex(this, i);
rects[i] = new Rect(x, 0, width, viewHeight);
x += width;
if (i < startIndex) offsetX += width;
if (createIdentifierGroup != null) createIdentifierGroup(i);
}
contentSize.x = x;
}
content.sizeDelta = contentSize;
if (startIndex >= 0)
{
if (vertical) contentPos.y = offsetY;
else contentPos.x = -offsetX;
if (gameObject.activeInHierarchy)
{
StopAllCoroutines();
StartCoroutine(ContentPos(contentPos));
}
}
else if (startIndex == -1)
{
if (vertical) contentPos.y = -viewHeight;
else contentPos.x = viewWidth;
content.anchoredPosition = contentPos;
}
Vector2 indexes = GetMinMaxVisibleIndex();
minVisibleIndex = (int)indexes.x;
maxVisibleIndex = (int)indexes.y;
if (numberOfCells > 0)
{
for (int i = minVisibleIndex; i <= maxVisibleIndex; i++)
{
AddCellAtIndex(i);
}
}
}
public void ToBottom()
{
RectTransform trans = transform as RectTransform;
ReloadData(-2);
if (this.content.sizeDelta.y > trans.rect.height)
{
content.anchoredPosition = new Vector2(content.anchoredPosition.x, this.content.sizeDelta.y + trans.rect.height);
}
}
public void InitReloadData(int startIndex = 0, bool cleanCell = false)
{
if (delegateNumberOfCells == null) return;
RectTransform trans = transform as RectTransform;
float viewWidth = trans.rect.width;
float viewHeight = trans.rect.height;
if (cleanCell) {
groupDict.Clear();
content.Clear();
}
else {
foreach(string identifier in groupDict.Keys) {
groupDict[identifier].QueueInvisible();
}
}
numberOfCells = delegateNumberOfCells(this);
rects = new Rect[numberOfCells];
float offsetX = 0f;
float offsetY = 0f;
float width = 0;
float x = 0;
float height = 0;
float y = 0;
Vector2 contentPos = content.anchoredPosition;
Vector2 contentSize = content.sizeDelta;
System.Action<int> createIdentifierGroup = null;
if (delegateIdentifierOfIndex == null)
{
if(groupDict.ContainsKey(DEFAULT_IDENTIFIER) == false) groupDict[DEFAULT_IDENTIFIER] = new TableViewGroup();
}
else
{
createIdentifierGroup = (i) => {
string identifier = delegateIdentifierOfIndex(this, i);
if (groupDict.ContainsKey(identifier) == false) groupDict[identifier] = new TableViewGroup();
};
}
if (vertical)
{
for (int i = 0; i < numberOfCells; i++)
{
height = delegateSizeOfIndex(this, i);
rects[i] = new Rect(0, -y, viewWidth, height);
y += height;
if (i < startIndex) offsetY += height;
if (createIdentifierGroup != null) createIdentifierGroup(i);
}
contentSize.y = y;
}
else
{
for (int i = 0; i < numberOfCells; i++)
{
width = delegateSizeOfIndex(this, i);
rects[i] = new Rect(x, 0, width, viewHeight);
x += width;
if (i < startIndex) offsetX += width;
if (createIdentifierGroup != null) createIdentifierGroup(i);
}
contentSize.x = x;
}
content.sizeDelta = contentSize;
if (startIndex >= 0)
{
if (vertical) contentPos.y = offsetY;
else contentPos.x = -offsetX;
content.anchoredPosition = contentPos;
}
else if (startIndex == -1)
{
if (vertical) contentPos.y = -viewHeight;
else contentPos.x = viewWidth;
content.anchoredPosition = contentPos;
}
Vector2 indexes = GetMinMaxVisibleIndex();
minVisibleIndex = (int)indexes.x;
maxVisibleIndex = (int)indexes.y;
if (numberOfCells > 0)
{
for (int i = minVisibleIndex; i <= maxVisibleIndex; i++)
{
AddCellAtIndex(i);
}
}
}
private IEnumerator ContentPos(Vector2 pos)
{
while (Vector2.Distance(content.anchoredPosition,pos) > 5)
{
content.anchoredPosition = Vector2.Lerp(content.anchoredPosition, pos, 0.7f);
yield return 1f;
}
content.anchoredPosition = pos;
}
string GetIdentifierForIndex(int index)
{
return delegateIdentifierOfIndex == null ? DEFAULT_IDENTIFIER : delegateIdentifierOfIndex(this, index);
}
public RectTransform DequeueReusabelCell(int index)
{
string identifier = GetIdentifierForIndex(index);
List<RectTransform> invisibilityCellQueue = groupDict[identifier].invisibilityCellQueue;
int count = invisibilityCellQueue.Count;
if (count > 0)
{
RectTransform trans = invisibilityCellQueue[count - 1];
invisibilityCellQueue.RemoveAt(count - 1);
trans.gameObject.SetActive(true);
return trans;
}
return null;
}
public bool enableDragControl = false;
public override void OnDrag(PointerEventData eventData)
{
if (!enableDragControl || (eventData.pointerCurrentRaycast.gameObject != null && isChild(eventData.pointerCurrentRaycast.gameObject.transform)))
base.OnDrag(eventData);
}
bool isChild(Transform t)
{
Transform[] children = this.transform.GetComponentsInChildren<Transform>();
for (int i = 0; i < children.Length; i++)
{
if (t.gameObject == children[i].gameObject)
return true;
}
return false;
}
}