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 cellPool = new Stack(); List activeCells = new List(); 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(); 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; } } }