c1_unity/Assets/Scripts/Component/UI/BFScrollRect/BFScrollRectMultSize.cs
2023-04-03 11:04:31 +08:00

491 lines
17 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace BF
{
public class BFScrollRectMultSize : BFScrollRectBase
{
public BFCell bfCell;
public float spacing;
public float topRecoveryOffset;
public float downRecoveryOffset;
public BFUIDirection direction;
public bool reverse = false;
Stack<BFCell> cellPool = new Stack<BFCell>();
List<BFCell> activeCells = new List<BFCell>();
int instantiateCount = 0;
int totalCount = 0;
void Awake()
{
if (bfCell.gameObject.activeSelf)
{
bfCell.gameObject.SetActive(false);
}
}
public override void RefillCells(int totalCount, int targetIndex)
{
this.totalCount = totalCount;
if (activeCells.Count != 0)
{
while (activeCells.Count != 0)
{
Pool(activeCells[0]);
}
UnityScrollRect.StopMovement();
}
ContentTrans.anchoredPosition = Vector2.zero;
ContentTrans.sizeDelta = direction == BFUIDirection.Vertical ?
new Vector2(ContentTrans.sizeDelta.x, 0) : new Vector2(0, ContentTrans.sizeDelta.y);
TryFullFill();
}
public override void SetTotalCount(int totalCount)
{
this.totalCount = totalCount;
if (totalCount < activeCells.Count)
{
for (int i = activeCells.Count - 1; i > totalCount - 1; i--)
{
Pool(activeCells[i]);
}
}
}
public override void RefreshAll()
{
int count = activeCells.Count;
for (int i = 0; i < count; i++)
{
var cell = activeCells[i];
var lastSize = direction == BFUIDirection.Vertical ? cell.Height + spacing : cell.Width + spacing;
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
var size = direction == BFUIDirection.Vertical ? cell.Height + spacing : cell.Width + spacing;
var sizeOffset = size - lastSize;
for (int j = i + 1; j < count; j++)
{
if(direction == BFUIDirection.Vertical)
{
activeCells[j].AnchoredPosition = new Vector2(activeCells[j].AnchoredPosition.x, activeCells[j].AnchoredPosition.y - sizeOffset);
}
else
{
activeCells[j].AnchoredPosition = new Vector2(activeCells[j].AnchoredPosition.x - sizeOffset, activeCells[j].AnchoredPosition.y);
}
}
if(direction == BFUIDirection.Vertical)
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, ContentTrans.sizeDelta.y + sizeOffset);
}
else
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, ContentTrans.sizeDelta.x + sizeOffset);
}
}
}
public override void SetSelected(int index)
{
selectedIndex = index;
int count = activeCells.Count;
for (int i = 0; i < count; i++)
{
var cell = activeCells[i];
Selected?.Invoke(cell.dataIndex == index, cell.objIndex);
}
}
public override void ClearCells()
{
while (activeCells.Count != 0)
{
Pool(activeCells[0]);
}
ContentTrans.anchoredPosition = Vector2.zero;
ContentTrans.sizeDelta = direction == BFUIDirection.Vertical ?
new Vector2(ContentTrans.sizeDelta.x, 0) : new Vector2(0, ContentTrans.sizeDelta.y);
}
public override void AnchoredPositionChange()
{
}
protected override void TryFullFill()
{
int i = 0;
while (CheckBorder() && i < totalCount)
{
i++;
}
}
bool CheckBorder()
{
if (activeCells.Count == 0)
{
TryStartAdd();
return false;
}
var cell = activeCells[0];
if(direction == BFUIDirection.Vertical)
{
if(reverse)
{
var delta = cell.AnchoredPosition.y + ContentTrans.anchoredPosition.y;
if (delta > 0 - topRecoveryOffset && TryAddUp())
{
return true;
}
}
else
{
var delta = cell.AnchoredPosition.y + ContentTrans.anchoredPosition.y;
if (delta < 0 + topRecoveryOffset && TryAddUp())
{
return true;
}
}
}
else
{
if(reverse)
{
var delta = cell.AnchoredPosition.x + ContentTrans.anchoredPosition.x;
if (delta < 0 + topRecoveryOffset && TryAddUp())
{
return true;
}
}
else
{
var delta = cell.AnchoredPosition.x + ContentTrans.anchoredPosition.x;
if (delta > 0 - topRecoveryOffset && TryAddUp())
{
return true;
}
}
}
cell = activeCells[activeCells.Count - 1];
if(direction == BFUIDirection.Vertical)
{
if(reverse)
{
var delta = cell.AnchoredPosition.y + cell.Height + spacing + ContentTrans.anchoredPosition.y;
if (delta < ViewPortTrans.sizeDelta.y + downRecoveryOffset && TryAddDown())
{
return true;
}
}
else
{
var delta = cell.AnchoredPosition.y - cell.Height - spacing + ContentTrans.anchoredPosition.y;
if (delta > -(ViewPortTrans.sizeDelta.y + downRecoveryOffset) && TryAddDown())
{
return true;
}
}
}
else
{
if(reverse)
{
var delta = cell.AnchoredPosition.x - cell.Width - spacing + ContentTrans.anchoredPosition.x;
if (delta > -(ViewPortTrans.sizeDelta.x + downRecoveryOffset) && TryAddDown())
{
return true;
}
}
else
{
var delta = cell.AnchoredPosition.x + cell.Width + spacing + ContentTrans.anchoredPosition.x;
if (delta < ViewPortTrans.sizeDelta.x + downRecoveryOffset && TryAddDown())
{
return true;
}
}
}
if (activeCells.Count <= 1)
{
return false;
}
if (NeedCull(activeCells[0]))
{
Pool(activeCells[0]);
return true;
}
if (NeedCull(activeCells[activeCells.Count - 1]))
{
Pool(activeCells[activeCells.Count - 1]);
return true;
}
return false;
}
void TryStartAdd()
{
if (totalCount == 0)
{
return;
}
var cell = GetCell();
cell.dataIndex = 1;
cell.name = StringConst.GetScrollRectCellName(0);
cell.gameObject.SetActive(true);
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
cell.CachedRectTransform.anchoredPosition = Vector2.zero;
if (direction == BFUIDirection.Vertical)
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, ContentTrans.sizeDelta.y + cell.Height + spacing);
}
else
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, ContentTrans.sizeDelta.x + cell.Width + spacing);
}
activeCells.Add(cell);
}
bool TryAddDown()
{
var downCell = activeCells[activeCells.Count - 1];
var downIndex = downCell.dataIndex;
if (downIndex == totalCount)
{
return false;
}
var cell = GetCell();
cell.dataIndex = downIndex + 1;
cell.name = StringConst.GetScrollRectCellName(cell.dataIndex - 1);
cell.gameObject.SetActive(true);
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
Vector2 pos;
if (direction == BFUIDirection.Vertical)
{
var d1 = downCell.AnchoredPosition.y;
var d2 = downCell.Height + spacing;
var d3 = cell.Height + spacing;
if(reverse)
{
pos = new Vector2(0.0f, d1 + d2);
cell.CachedRectTransform.anchoredPosition = pos;
if (ContentTrans.sizeDelta.y <= cell.AnchoredPosition.y + d3 * 0.5f)
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, ContentTrans.sizeDelta.y + d3);
}
}
else
{
pos = new Vector2(0.0f, d1 - d2);
cell.CachedRectTransform.anchoredPosition = pos;
if (ContentTrans.sizeDelta.y <= -cell.AnchoredPosition.y + d3 * 0.5f)
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, ContentTrans.sizeDelta.y + d3);
}
}
}
else
{
var d1 = downCell.AnchoredPosition.x;
var d2 = downCell.Width + spacing;
var d3 = cell.Width + spacing;
if(reverse)
{
pos = new Vector2(d1 - d2, 0.0f);
cell.CachedRectTransform.anchoredPosition = pos;
if (ContentTrans.sizeDelta.x <= -cell.AnchoredPosition.x + d3 * 0.5f)
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, ContentTrans.sizeDelta.x + d3);
}
}
else
{
pos = new Vector2(d1 + d2, 0.0f);
cell.CachedRectTransform.anchoredPosition = pos;
if (ContentTrans.sizeDelta.x <= cell.AnchoredPosition.x + d3 * 0.5f)
{
ContentTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, ContentTrans.sizeDelta.x + d3);
}
}
}
activeCells.Add(cell);
return true;
}
bool TryAddUp()
{
var topCell = activeCells[0];
var topIndex = topCell.dataIndex;
if (topIndex == 1)
{
return false;
}
var cell = GetCell();
cell.dataIndex = topIndex - 1;
cell.name = StringConst.GetScrollRectCellName(cell.dataIndex - 1);
cell.gameObject.SetActive(true);
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
var d1 = direction == BFUIDirection.Vertical ?
cell.Height + spacing :
cell.Width + spacing;
if(reverse)
{
var pos = direction == BFUIDirection.Vertical ?
new Vector2(0.0f, topCell.AnchoredPosition.y - d1) :
new Vector2(topCell.AnchoredPosition.x + d1, 0.0f);
cell.CachedRectTransform.anchoredPosition = pos;
}
else
{
var pos = direction == BFUIDirection.Vertical ?
new Vector2(0.0f, topCell.AnchoredPosition.y + d1) :
new Vector2(topCell.AnchoredPosition.x - d1, 0.0f);
cell.CachedRectTransform.anchoredPosition = pos;
}
activeCells.Insert(0, cell);
return true;
}
BFCell GetCell()
{
if (cellPool.Count > 0)
{
return cellPool.Pop();
}
else
{
var t = Instantiate(bfCell.CachedRectTransform);
t.SetParent(ContentTrans);
t.localScale = Vector3.one;
t.anchoredPosition3D = Vector3.zero;
instantiateCount++;
var newCell = t.GetComponent<BFCell>();
newCell.objIndex = instantiateCount;
OnInstantiateCell?.Invoke(newCell.gameObject);
return newCell;
}
}
void Pool(BFCell cell)
{
activeCells.Remove(cell);
cell.gameObject.SetActive(false);
cellPool.Push(cell);
}
bool NeedCull(BFCell cell)
{
if (activeCells.IndexOf(cell) == 0)
{
if(direction == BFUIDirection.Vertical)
{
if(reverse)
{
var d1 = cell.AnchoredPosition.y + cell.Height + spacing + ContentTrans.anchoredPosition.y;
if (d1 < -(0.01 + topRecoveryOffset))
{
return true;
}
}
else
{
var d1 = cell.AnchoredPosition.y - cell.Height - spacing + ContentTrans.anchoredPosition.y;
if (d1 > 0.01 + topRecoveryOffset)
{
return true;
}
}
}
else
{
if(reverse)
{
var d1 = cell.AnchoredPosition.x - cell.Width - spacing + ContentTrans.anchoredPosition.x;
if (d1 > 0.01 + topRecoveryOffset)
{
return true;
}
}
else
{
var d1 = cell.AnchoredPosition.x + cell.Width + spacing + ContentTrans.anchoredPosition.x;
if (d1 < -(0.01 + topRecoveryOffset))
{
return true;
}
}
}
}
if(direction == BFUIDirection.Vertical)
{
if(reverse)
{
var d2 = cell.AnchoredPosition.y + ContentTrans.anchoredPosition.y;
var d3 = ViewPortTrans.sizeDelta.y;
if (d2 > d3 + 0.01 + downRecoveryOffset)
{
return true;
}
}
else
{
var d2 = cell.AnchoredPosition.y + ContentTrans.anchoredPosition.y;
var d3 = -ViewPortTrans.sizeDelta.y;
if (d2 < d3 - (0.01 + downRecoveryOffset))
{
return true;
}
}
}
else
{
if(reverse)
{
var d2 = cell.AnchoredPosition.x + ContentTrans.anchoredPosition.x;
var d3 = -ViewPortTrans.sizeDelta.x;
if (d2 < d3 - (0.01 + downRecoveryOffset))
{
return true;
}
}
else
{
var d2 = cell.AnchoredPosition.x + ContentTrans.anchoredPosition.x;
var d3 = ViewPortTrans.sizeDelta.x;
if (d2 > d3 + 0.01 + downRecoveryOffset)
{
return true;
}
}
}
if (cell.dataIndex > totalCount)
{
return true;
}
return false;
}
}
}