2023-04-28 17:04:52 +08:00

647 lines
25 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace BF
{
public class BFScrollRectCommon : BFScrollRectBase
{
public BFCell bfCell;
// public float spacing;
public int topRecoveryOffset;
public int downRecoveryOffset;
public BFUIDirection direction;
public bool reverse = false;
Stack<BFCell> cellPool = new Stack<BFCell>();
List<BFCell> activeCells = new List<BFCell>();
float cellSize;
int instantiateCount = 0;
int totalCount = 0;
int tmpTotalCount = 0;
public float cellWidth = 0.0f;
public float CellWidth
{
get { return cellWidth;}
set {
cellWidth = value;
UpdateAllCellPosition();
}
}
public float cellHeight = 0.0f;
public float CellHeight
{
get { return cellHeight;}
set {
cellHeight = value;
UpdateAllCellPosition();
}
}
private int minIdx = 0;
private int maxIdx = 0;
private int tmpMinIdx = 0;
private int tmpMaxIdx = 0;
private int maxLine = 0;
private Vector2 curAnchoredPosition = new Vector2(0.0f, 0.0f);
public int perLineNum = 1;
void Awake()
{
if (bfCell.gameObject.activeSelf)
{
bfCell.gameObject.SetActive(false);
}
if (direction == BFUIDirection.Vertical)
{
if (reverse)
{
ContentTrans.anchorMax = new Vector2(0.0f, 0.0f);
ContentTrans.anchorMin = new Vector2(0.0f, 0.0f);
ContentTrans.pivot = new Vector2(0.0f, 0.0f);
ContentTrans.anchoredPosition = Vector2.zero;
}
else
{
ContentTrans.anchorMax = new Vector2(0.0f, 1.0f);
ContentTrans.anchorMin = new Vector2(0.0f, 1.0f);
ContentTrans.pivot = new Vector2(0.0f, 1.0f);
ContentTrans.anchoredPosition = Vector2.zero;
}
}
else
{
if (reverse)
{
ContentTrans.anchorMax = new Vector2(1.0f, 1.0f);
ContentTrans.anchorMin = new Vector2(1.0f, 1.0f);
ContentTrans.pivot = new Vector2(1.0f, 1.0f);
ContentTrans.anchoredPosition = new Vector2(1.0f, 1.0f);
}
else
{
ContentTrans.anchorMax = new Vector2(0.0f, 0.0f);
ContentTrans.anchorMin = new Vector2(0.0f, 0.0f);
ContentTrans.pivot = new Vector2(0.0f, 0.0f);
ContentTrans.anchoredPosition = Vector2.zero;
}
}
}
public override void RefillCells(int totalCount, int targetIndex)
{
SetTotalCount(totalCount);
if (activeCells.Count != 0)
{
while (activeCells.Count != 0)
{
Pool(activeCells[activeCells.Count - 1]);
}
UnityScrollRect.StopMovement();
}
minIdx = 0;
maxIdx = 0;
if (targetIndex > 0)
{
MoveToIndex(targetIndex);
}
TryFullFill();
AnchoredPositionChange();
}
public override void SetTotalCount(int totalCount)
{
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "totalCount = " + totalCount.ToString());
this.totalCount = totalCount;
if (totalCount < activeCells.Count)
{
for (int i = activeCells.Count - 1; i > totalCount - 1; i--)
{
Pool(activeCells[i]);
}
}
maxLine = Mathf.CeilToInt(totalCount*1.0f/perLineNum);
if (direction == BFUIDirection.Vertical)
{
float maxHeight = Mathf.Max(UnityScrollRect.viewport.rect.height, maxLine*cellHeight + topRecoveryOffset + downRecoveryOffset);
ContentTrans.sizeDelta = new Vector2(ContentTrans.sizeDelta.x, maxHeight);
// cellWidth = (int)UnityScrollRect.viewport.rect.width;
if (reverse)
{
float posY = UnityScrollRect.content.anchoredPosition.y;
float minPosY = Mathf.Floor(UnityScrollRect.viewport.rect.height) - maxHeight;
if (posY < minPosY)
{
UnityScrollRect.content.anchoredPosition = new Vector2(UnityScrollRect.content.anchoredPosition.x, minPosY);
}
}
else
{
float posY = UnityScrollRect.content.anchoredPosition.y;
float maxPosY = maxHeight - Mathf.Floor(UnityScrollRect.viewport.rect.height);
if (posY > maxPosY)
{
UnityScrollRect.content.anchoredPosition = new Vector2(UnityScrollRect.content.anchoredPosition.x, maxPosY);
}
}
}
else
{
float maxWidth = Mathf.Max(UnityScrollRect.viewport.rect.width, maxLine*cellWidth + topRecoveryOffset + downRecoveryOffset);
ContentTrans.sizeDelta = new Vector2(maxWidth, ContentTrans.sizeDelta.y);
// cellHeight = (int)UnityScrollRect.viewport.rect.height;
if (reverse)
{
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "UnityScrollRect.content.anchoredPosition.x = " + UnityScrollRect.content.anchoredPosition.x);
float posX = UnityScrollRect.content.anchoredPosition.x;
float maxPosX = maxWidth - Mathf.Floor(UnityScrollRect.viewport.rect.width);
if (posX > maxPosX)
{
UnityScrollRect.content.anchoredPosition = new Vector2(maxPosX, UnityScrollRect.content.anchoredPosition.y);
}
}
else
{
float posX = UnityScrollRect.content.anchoredPosition.x;
float minPosX = Mathf.Floor(UnityScrollRect.viewport.rect.width) - maxWidth;
if (posX < minPosX)
{
UnityScrollRect.content.anchoredPosition = new Vector2(minPosX, UnityScrollRect.content.anchoredPosition.y);
}
}
}
// minIdx = Mathf.Max(1, minIdx);
// maxIdx = Mathf.Min(this.totalCount, maxIdx);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", " ContentTrans.sizeDelta.x = " + ContentTrans.sizeDelta.x);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", " ContentTrans.sizeDelta.y = " + ContentTrans.sizeDelta.y);
}
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 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[activeCells.Count - 1]);
}
if (direction == BFUIDirection.Vertical)
{
ContentTrans.anchoredPosition = Vector2.zero;
}
else
{
if (reverse)
{
ContentTrans.anchoredPosition = new Vector2(1.0f, 1.0f);
}
else
{
ContentTrans.anchoredPosition = Vector2.zero;
}
}
minIdx = 0;
maxIdx = 0;
}
public override void AnchoredPositionChange()
{
if (Mathf.Abs(curAnchoredPosition.x - UnityScrollRect.content.anchoredPosition.x) >= 1 || Mathf.Abs(curAnchoredPosition.y - UnityScrollRect.content.anchoredPosition.y) >= 1)
{
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "diffX = " + (curAnchoredPosition.x - UnityScrollRect.content.anchoredPosition.x));
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "diffY = " + (curAnchoredPosition.y - UnityScrollRect.content.anchoredPosition.y));
curAnchoredPosition.x = UnityScrollRect.content.anchoredPosition.x;
curAnchoredPosition.y = UnityScrollRect.content.anchoredPosition.y;
OnAnchoredPositionAction?.Invoke(UnityScrollRect.content.anchoredPosition.x, UnityScrollRect.content.anchoredPosition.y);
}
}
protected override void TryFullFill()
{
CheckBorder();
}
void calculateIndex()
{
if (direction == BFUIDirection.Vertical)
{
float posY = UnityScrollRect.content.anchoredPosition.y;
if (reverse)
{
// float posX = totalMaxWidth - (Mathf.Floor(UnityScrollRect.viewport.rect.width) - UnityScrollRect.content.anchoredPosition.x);
tmpMinIdx = Mathf.CeilToInt(-(posY + topRecoveryOffset)/cellHeight);
tmpMaxIdx = Mathf.CeilToInt((Mathf.Floor(UnityScrollRect.viewport.rect.height) - (posY + topRecoveryOffset))/cellHeight);
}
else
{
tmpMinIdx = Mathf.CeilToInt((posY - topRecoveryOffset)/cellHeight);
tmpMaxIdx = Mathf.CeilToInt((posY - topRecoveryOffset + Mathf.Floor(UnityScrollRect.viewport.rect.height))/cellHeight);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "posY = " + posY);
}
}
else
{
float posX = UnityScrollRect.content.anchoredPosition.x;
if (reverse)
{
// float posX = totalMaxWidth - (Mathf.Floor(UnityScrollRect.viewport.rect.width) - UnityScrollRect.content.anchoredPosition.x);
tmpMinIdx = Mathf.CeilToInt((posX - topRecoveryOffset)/cellWidth);
tmpMaxIdx = Mathf.CeilToInt((Mathf.Floor(UnityScrollRect.viewport.rect.width) + (posX - topRecoveryOffset))/cellWidth);
}
else
{
tmpMinIdx = Mathf.CeilToInt(-(posX + topRecoveryOffset)/cellWidth);
tmpMaxIdx = Mathf.CeilToInt((Mathf.Floor(UnityScrollRect.viewport.rect.width) - (posX + topRecoveryOffset))/cellWidth);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "posX = " + posX);
}
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "posX = " + posX);
}
tmpMinIdx = Mathf.Max(1, tmpMinIdx);
tmpMaxIdx = Mathf.Min(maxLine, tmpMaxIdx);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "tmpMinIdx = " + tmpMinIdx + " tmpMaxIdx = " + tmpMaxIdx);
}
bool CheckBorder()
{
calculateIndex();
if (minIdx == 0)
{
minIdx = tmpMinIdx;
maxIdx = tmpMaxIdx;
tmpTotalCount = totalCount;
int minIdxMult = (minIdx - 1)*perLineNum + 1;
int maxIdxMult = maxIdx*perLineNum;
maxIdxMult = Mathf.Min(maxIdxMult, totalCount);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "===== 1 minIdxMult = " + minIdxMult + " maxIdxMult = " + maxIdxMult);
for (int i = minIdxMult; i <= maxIdxMult; i++)
{
TryStartAdd(i, false);
}
AnchoredPositionChange();
return false;
}
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "===== 1 tmpMinIdx = " + tmpMinIdx + " tmpMaxIdx = " + tmpMaxIdx);
if (tmpMinIdx == minIdx && tmpMaxIdx == maxIdx && tmpTotalCount == totalCount)
{
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "===== 3 minIdx = " + minIdx + " maxIdx = " + maxIdx);
AnchoredPositionChange();
return false;
}
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "===== 2 tmpMinIdx = " + tmpMinIdx + " tmpMaxIdx = " + tmpMaxIdx);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "minIdx = " + minIdx + " maxIdx = " + maxIdx);
int minIdxMult2 = (tmpMinIdx - 1)*perLineNum + 1;
int maxIdxMult2 = tmpMaxIdx*perLineNum;
maxIdxMult2 = Mathf.Min(maxIdxMult2, totalCount);
for (int ii = activeCells.Count - 1; ii >= 0; ii--)
{
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "================================1 minIdx = " + i);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", activeCells[ii].dataIndex.ToString());
if (activeCells[ii] && (activeCells[ii].dataIndex < minIdxMult2 || activeCells[ii].dataIndex > maxIdxMult2))
{
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "activeCells[ii].dataIndex = " + activeCells[ii].dataIndex);
Pool(activeCells[ii]);
}
}
int minIdxMult1 = (tmpMinIdx - 1)*perLineNum + 1;
int maxIdxMult1 = tmpMaxIdx*perLineNum;
maxIdxMult1 = Mathf.Min(maxIdxMult1, totalCount);
for (int i = minIdxMult1; i <= maxIdxMult1; i++)
{
bool notFind = true;
for (int ii = 0; ii < activeCells.Count; ii++)
{
if (activeCells[ii] && activeCells[ii].dataIndex == i)
{
notFind = false;
break;
}
}
if(notFind)
{
if (minIdx > tmpMinIdx)
{
TryStartAdd(i, true);
}
else
{
TryStartAdd(i, false);
}
}
}
// if (minIdx > tmpMinIdx)
// {
// float minIdxMult1 = (tmpMinIdx - 1)*perLineNum + 1;
// float minIdxMult2 = (minIdx - 1)*perLineNum;
// for (float i = minIdxMult1; i <= minIdxMult2; i++)
// {
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "minIdx i = " + i);
// TryStartAdd(i, true);
// }
// }
// if (tmpMaxIdx > maxIdx || tmpTotalCount != totalCount)
// {
// float maxIdxMult1 = maxIdx*perLineNum + 1;
// float maxIdxMult2 = tmpMaxIdx*perLineNum;
// maxIdxMult2 = Mathf.Min(maxIdxMult2, totalCount);
// // BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "maxIdxMult2 = " + maxIdxMult2);
// for (float i = maxIdxMult1; i <= maxIdxMult2; i++)
// {
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "maxIdx i = " + i);
// TryStartAdd(i, false);
// }
// }
minIdx = tmpMinIdx;
maxIdx = tmpMaxIdx;
tmpTotalCount = totalCount;
AnchoredPositionChange();
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "minIdx = " + minIdx + " maxIdx = " + maxIdx + " maxCellNum = " + (int)Mathf.Ceil(UnityScrollRect.viewport.rect.width/cellWidth));
return false;
}
private float GetPositionXByIndex(int index)
{
float posX = 0.0f;
if (direction == BFUIDirection.Vertical)
{
if (reverse)
{
float cellWidth1 = UnityScrollRect.viewport.rect.width/perLineNum;
float idx = (index - 1.0f)%perLineNum + 1.0f;
posX = (idx - 0.5f) * cellWidth1;
}
else
{
float cellWidth1 = UnityScrollRect.viewport.rect.width/perLineNum;
float idx = (index - 1.0f)%perLineNum + 1.0f;
posX = (idx - 0.5f) * cellWidth1;
}
}
else
{
if (reverse)
{
float idxX = Mathf.Ceil(index*1.0f/perLineNum);
posX = -(idxX - 0.5f)*cellWidth - topRecoveryOffset;
}
else
{
float idxX = Mathf.Ceil(index*1.0f/perLineNum);
posX = (idxX - 0.5f)*cellWidth + topRecoveryOffset;
}
}
return posX;
}
private float GetPositionYByIndex(int index)
{
float posY = 0.0f;
if (direction == BFUIDirection.Vertical)
{
if (reverse)
{
float idxY = Mathf.Ceil(index*1.0f/perLineNum);
posY = (idxY - 0.5f)*cellHeight + topRecoveryOffset;
}
else
{
float idxY = Mathf.Ceil(index*1.0f/perLineNum);
posY = -(idxY - 0.5f)*cellHeight - topRecoveryOffset;
}
}
else
{
if (reverse)
{
float cellHeight1 = UnityScrollRect.viewport.rect.height/perLineNum;
float offset = UnityScrollRect.viewport.rect.height/perLineNum/2.0f;
float idx = (index - 1.0f)%perLineNum + 1.0f;
posY = -(offset + (idx - 1.0f)*cellHeight1);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "index = " + index + " posY = " + posY + " offset = " + offset);
}
else
{
float cellHeight1 = UnityScrollRect.viewport.rect.height/perLineNum;
float offset = UnityScrollRect.viewport.rect.height - UnityScrollRect.viewport.rect.height/perLineNum/2.0f;
float idx = (index - 1.0f)%perLineNum + 1.0f;
posY = offset - (idx - 1.0f)*cellHeight1;
}
}
return posY;
}
void TryStartAdd(int index, bool addMin)
{
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "index = " + index);
if (totalCount == 0)
{
return;
}
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "cellWidth = " + cellWidth + " index - 0.5 = " + (index - 0.5));
float posX = GetPositionXByIndex(index);
float posY = GetPositionYByIndex(index);
// BFLog.LogDebug(BFLog.DEBUG_GAME_LAUNCH, "red", "posX = " + posX + " posY = " + posY + " index = " + index);
var cell = GetCell();
cell.name = StringConst.GetScrollRectCellName(index - 1);
cell.dataIndex = index;
if (reverse)
{
if (direction == BFUIDirection.Vertical)
{
cell.CachedRectTransform.anchorMin = new Vector2(0.0f, 0.0f);
cell.CachedRectTransform.anchorMax = new Vector2(0.0f, 0.0f);
}
else
{
cell.CachedRectTransform.anchorMin = new Vector2(1.0f, 1.0f);
cell.CachedRectTransform.anchorMax = new Vector2(1.0f, 1.0f);
}
}
else
{
if (direction == BFUIDirection.Vertical)
{
cell.CachedRectTransform.anchorMin = new Vector2(0.0f, 1.0f);
cell.CachedRectTransform.anchorMax = new Vector2(0.0f, 1.0f);
}
else
{
cell.CachedRectTransform.anchorMin = new Vector2(0.0f, 0.0f);
cell.CachedRectTransform.anchorMax = new Vector2(0.0f, 0.0f);
}
}
cell.CachedRectTransform.pivot = new Vector2(0.5f, 0.5f);
cell.CachedRectTransform.anchoredPosition = new Vector2(posX, posY);
if (addMin)
{
activeCells.Insert(0, cell);
}
else
{
activeCells.Add(cell);
}
cell.gameObject.SetActive(true);
RefreshAction?.Invoke(cell.dataIndex, cell.objIndex);
}
BFCell GetCell()
{
if (cellPool.Count > 0)
{
return cellPool.Pop();
}
else
{
var t = Instantiate(bfCell.CachedRectTransform);
t.SetParent(ContentTrans);
t.localScale = bfCell.CachedRectTransform.localScale;
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);
}
public override void MoveToIndex(int index)
{
if (index > totalCount)
{
return;
}
if (direction == BFUIDirection.Vertical)
{
float moveDistance = cellHeight * Mathf.Floor((index - 1)*1.0f/perLineNum);
float moveHeight = Mathf.Min(moveDistance, ContentTrans.rect.size.y - ViewPortTrans.rect.size.y);
if(this.reverse)
{
ContentTrans.anchoredPosition = new Vector2(ContentTrans.anchoredPosition.x, -moveHeight);
}
else
{
ContentTrans.anchoredPosition = new Vector2(ContentTrans.anchoredPosition.x, moveHeight);
}
}
else
{
float moveDistance = cellWidth * Mathf.Floor((index - 1)*1.0f/perLineNum);
float moveWidth = Mathf.Min(moveDistance, ContentTrans.rect.size.x - ViewPortTrans.rect.size.x);
if(this.reverse)
{
ContentTrans.anchoredPosition = new Vector2(moveWidth, ContentTrans.anchoredPosition.y);
}
else
{
ContentTrans.anchoredPosition = new Vector2(-moveWidth, ContentTrans.anchoredPosition.y);
}
}
}
public override void RemoveCell(int index)
{
if (totalCount <= 0)
{
return;
}
var activeCount = activeCells.Count;
if (activeCells[activeCount - 1].dataIndex == totalCount && activeCells[0].dataIndex > index)
{
foreach (var cell in activeCells)
{
cell.dataIndex -= 1;
}
}
SetTotalCount(totalCount - 1);
TryFullFill();
RefreshAll();
}
public void StopMovement()
{
UnityScrollRect.StopMovement();
}
public void UpdateAllCellPosition()
{
for (int i = 0; i < activeCells.Count; i++)
{
float posX = GetPositionXByIndex(activeCells[i].dataIndex);
float posY = GetPositionYByIndex(activeCells[i].dataIndex);
activeCells[i].CachedRectTransform.anchoredPosition = new Vector2(posX, posY);
}
}
public void SetCellWidth(float width)
{
cellWidth = width;
UpdateAllCellPosition();
}
public void SetCellHeight(float height)
{
cellHeight = height;
UpdateAllCellPosition();
}
public void SetPerLineNum(int num)
{
perLineNum = num;
UpdateAllCellPosition();
}
public void SetTopRecoveryOffset(int num)
{
topRecoveryOffset = num;
UpdateAllCellPosition();
}
public void SetDownRecoveryOffset(int num)
{
downRecoveryOffset = num;
UpdateAllCellPosition();
}
public int GetTopRecoveryOffset()
{
return topRecoveryOffset;
}
public int GetDownRecoveryOffset()
{
return downRecoveryOffset;
}
}
}