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