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

380 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace BF
{
public class BFScrollRectMultCell : BFScrollRectBase
{
public BFCell[] bfCells;
public float spacing;
public float padding;
public float topRecoveryOffset;
public float downRecoveryOffset;
public int preLineCount = 4;
public BFUIDirection direction;
List<BFCell> activeCells = new List<BFCell>();
Dictionary<int, Stack<BFCell>> cellPool = new Dictionary<int, Stack<BFCell>>();
float lineSize;
float cellSize;
int instantiateCount = 0;
int totalCount = 0;
int topFillCount;
int bottomFillCount;
Func<int, int> GetCellIndex;
void Awake()
{
lineSize = direction == BFUIDirection.Vertical ? bfCells[0].Height + spacing : bfCells[0].Width + spacing;
cellSize = direction == BFUIDirection.Vertical ? bfCells[0].Width + padding : bfCells[0].Height + padding;
int i = 1;
foreach (var cell in bfCells)
{
if (cell.gameObject.activeSelf)
{
cell.gameObject.SetActive(false);
}
cellPool.Add(i, new Stack<BFCell>());
i++;
}
}
int GetTotalLines(int totalCount)
{
if (totalCount % preLineCount == 0)
{
return totalCount / preLineCount;
}
return totalCount / preLineCount + 1;
}
public void SetGetCellIndexFunc(Func<int, int> getCellIndex)
{
GetCellIndex = getCellIndex;
}
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;
if (direction == BFUIDirection.Vertical)
{
ContentTrans.sizeDelta = new Vector2(ContentTrans.sizeDelta.x, lineSize * GetTotalLines(totalCount) - spacing);
}
else
{
ContentTrans.sizeDelta = new Vector2(lineSize * GetTotalLines(totalCount) - spacing, 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]);
if(bottomFillCount > 0)
{
bottomFillCount--;
}
else
{
if(totalCount <= preLineCount)
{
topFillCount--;
}
else
{
bottomFillCount = preLineCount - 1;
}
}
}
}
if (direction == BFUIDirection.Vertical)
{
ContentTrans.sizeDelta = new Vector2(ContentTrans.sizeDelta.x, lineSize * GetTotalLines(totalCount) - spacing);
}
else
{
ContentTrans.sizeDelta = new Vector2(lineSize * totalCount - spacing, ContentTrans.sizeDelta.y);
}
}
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 RefreshAll()
{
int count = activeCells.Count;
for (int i = 0; i < count; i++)
{
var cell = activeCells[i];
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
}
}
public override void ClearCells()
{
while (activeCells.Count != 0)
{
Pool(activeCells[0]);
}
ContentTrans.anchoredPosition = Vector2.zero;
}
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];
var delta = direction == BFUIDirection.Vertical ?
cell.AnchoredPosition.y + ContentTrans.anchoredPosition.y :
cell.AnchoredPosition.x + ContentTrans.anchoredPosition.x;
if (delta < 0 + topRecoveryOffset && TryAddUp())
{
return true;
}
if (topFillCount < preLineCount && TryAddUp())
{
return true;
}
cell = activeCells[activeCells.Count - 1];
delta = direction == BFUIDirection.Vertical ?
cell.AnchoredPosition.y - lineSize + ContentTrans.anchoredPosition.y :
cell.AnchoredPosition.x - lineSize + ContentTrans.anchoredPosition.x;
if (delta > -(ViewPortTrans.sizeDelta.y + downRecoveryOffset) && TryAddDown())
{
return true;
}
if (bottomFillCount < preLineCount && TryAddDown())
{
return true;
}
if (activeCells.Count <= preLineCount)
{
return false;
}
if (NeedCull(activeCells[0]))
{
Pool(activeCells[0]);
if(topFillCount == 0)
{
topFillCount = preLineCount - 1;
}
else
{
topFillCount--;
}
return true;
}
if (NeedCull(activeCells[activeCells.Count - 1]))
{
Pool(activeCells[activeCells.Count - 1]);
if(bottomFillCount == 0)
{
bottomFillCount = preLineCount - 1;
}
else
{
bottomFillCount--;
}
return true;
}
return false;
}
void TryStartAdd()
{
if (totalCount == 0)
{
return;
}
var cell = GetCell(1);
topFillCount = 1;
cell.CachedRectTransform.anchoredPosition = Vector2.zero;
activeCells.Add(cell);
cell.gameObject.SetActive(true);
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
}
bool TryAddUp()
{
var topIndex = activeCells[0].dataIndex;
if (topIndex == 1 && (topFillCount == preLineCount || activeCells.Count == totalCount))
{
return false;
}
BFCell cell;
if (topFillCount == preLineCount)
{
topFillCount = 0;
cell = GetCell(topIndex - preLineCount);
}
else
{
cell = GetCell(topIndex + topFillCount);
}
var x = direction == BFUIDirection.Vertical ? topFillCount * cellSize : -GetLineIndex(cell.dataIndex) * lineSize;
var y = direction == BFUIDirection.Vertical ? -GetLineIndex(cell.dataIndex) * lineSize : topFillCount * cellSize;
cell.CachedRectTransform.anchoredPosition = new Vector2(x, y);
cell.gameObject.SetActive(true);
topFillCount++;
if (topFillCount == activeCells.Count)
{
activeCells.Add(cell);
}
else
{
activeCells.Insert(topFillCount - 1, cell);
}
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
return true;
}
bool TryAddDown()
{
var downIndex = activeCells[activeCells.Count - 1].dataIndex;
if (downIndex == totalCount)
{
return false;
}
if (bottomFillCount == preLineCount)
{
bottomFillCount = 0;
}
var cell = GetCell(downIndex + 1);
var x = direction == BFUIDirection.Vertical ? bottomFillCount * cellSize : -GetLineIndex(cell.dataIndex) * lineSize;
var y = direction == BFUIDirection.Vertical ? -GetLineIndex(cell.dataIndex) * lineSize : bottomFillCount * cellSize;
cell.CachedRectTransform.anchoredPosition = new Vector2(x, y);
activeCells.Add(cell);
cell.gameObject.SetActive(true);
bottomFillCount++;
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
return true;
}
int GetLineIndex(int index)
{
if (index % preLineCount == 0)
{
return index / preLineCount - 1;
}
return index / preLineCount;
}
BFCell GetCell(int dataIndex)
{
var index = GetCellIndex(dataIndex);
if (cellPool[index].Count > 0)
{
return cellPool[index].Pop();
}
else
{
var t = Instantiate(bfCells[index].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);
newCell.dataIndex = dataIndex;
return newCell;
}
}
void Pool(BFCell cell)
{
cell.gameObject.SetActive(false);
activeCells.Remove(cell);
var index = GetCellIndex(cell.dataIndex);
cellPool[index].Push(cell);
}
bool NeedCull(BFCell cell)
{
if (activeCells.IndexOf(cell) == 0)
{
var d1 = direction == BFUIDirection.Vertical ?
cell.AnchoredPosition.y - lineSize + ContentTrans.anchoredPosition.y :
cell.AnchoredPosition.x - lineSize + ContentTrans.anchoredPosition.x;
if (d1 > 0.01 + topRecoveryOffset)
{
return true;
}
}
var d2 = direction == BFUIDirection.Vertical ?
cell.AnchoredPosition.y + ContentTrans.anchoredPosition.y :
cell.AnchoredPosition.x + ContentTrans.anchoredPosition.x;
var d3 = direction == BFUIDirection.Vertical ?
-ViewPortTrans.sizeDelta.y : -ViewPortTrans.sizeDelta.x;
if (d2 < d3 - (0.01 + downRecoveryOffset))
{
return true;
}
if (cell.dataIndex > totalCount)
{
return true;
}
return false;
}
}
}