From bcb13638c1856be83a6e71584224b44f8327551c Mon Sep 17 00:00:00 2001 From: LiRuoChen <571244399@qq.com> Date: Tue, 28 Apr 2026 14:15:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E6=AD=A3=E4=BA=86=E9=94=99=E5=88=AB?= =?UTF-8?q?=E5=AD=97=E3=80=82=20=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E8=AE=A1=E7=AE=97=E6=B5=81=E7=A8=8B=EF=BC=8C=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E5=8F=AF=E4=BB=A5=E6=89=8B=E5=8A=A8=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E8=A1=8C=E5=88=97=E6=95=B0=E9=87=8F=E4=BA=86?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OverrideLayout/XericScrollRectEditor.cs | 4 + .../Core/Interface/IUIVesselVisibalControl.cs | 11 +- Runtime/Core/Vessel/VesselBase.cs | 2 +- Runtime/Helper/GridLayoutCalculator.cs | 93 +++---- Runtime/Helper/UIVesselHelp.cs | 6 +- Runtime/OverrideLayout/XericScrollRect.cs | 233 ++++++++++++------ 6 files changed, 224 insertions(+), 125 deletions(-) diff --git a/Editor/OverrideLayout/XericScrollRectEditor.cs b/Editor/OverrideLayout/XericScrollRectEditor.cs index 51b201f..b3f5b9e 100644 --- a/Editor/OverrideLayout/XericScrollRectEditor.cs +++ b/Editor/OverrideLayout/XericScrollRectEditor.cs @@ -23,6 +23,7 @@ namespace XericUIEditor.OverrideLayout SerializedProperty m_startAxis; SerializedProperty m_childAlignment; SerializedProperty m_constraint; + SerializedProperty m_constraintCount; protected override void OnEnable() { @@ -41,6 +42,7 @@ namespace XericUIEditor.OverrideLayout m_startAxis = serializedObject.FindProperty("m_startAxis"); m_childAlignment = serializedObject.FindProperty("m_childAlignment"); m_constraint = serializedObject.FindProperty("m_constraint"); + m_constraintCount = serializedObject.FindProperty("m_constraintCount"); } public override void OnInspectorGUI() @@ -68,6 +70,8 @@ namespace XericUIEditor.OverrideLayout EditorGUILayout.PropertyField(m_startAxis); EditorGUILayout.PropertyField(m_childAlignment); EditorGUILayout.PropertyField(m_constraint); + if (m_constraint.enumValueIndex != (int)UnityEngine.UI.GridLayoutGroup.Constraint.Flexible) + EditorGUILayout.PropertyField(m_constraintCount); EditorGUI.indentLevel--; } diff --git a/Runtime/Core/Interface/IUIVesselVisibalControl.cs b/Runtime/Core/Interface/IUIVesselVisibalControl.cs index d6cc6a6..0ee91aa 100644 --- a/Runtime/Core/Interface/IUIVesselVisibalControl.cs +++ b/Runtime/Core/Interface/IUIVesselVisibalControl.cs @@ -1,4 +1,6 @@ -namespace XericUI.Core.Interface +using XericUI.Helper; + +namespace XericUI.Core.Interface { /// /// Xeric UI Vessel容器控制接口 @@ -12,11 +14,12 @@ /// /// 当前元素处于可见范围时(预载范围) /// - public void UnderVisibal(); + public void UnderVisible(); /// /// 当前元素离开可见范围时(预载范围) /// - - public void OutOfVisibal(); + public void OutOfVisible(); + + public void UpdateLayout(GridLayoutCalculator.LayoutItem layoutData); } } \ No newline at end of file diff --git a/Runtime/Core/Vessel/VesselBase.cs b/Runtime/Core/Vessel/VesselBase.cs index b9e6062..cd183b3 100644 --- a/Runtime/Core/Vessel/VesselBase.cs +++ b/Runtime/Core/Vessel/VesselBase.cs @@ -2,6 +2,6 @@ { public class VesselBase { - + public string VesselName; } } \ No newline at end of file diff --git a/Runtime/Helper/GridLayoutCalculator.cs b/Runtime/Helper/GridLayoutCalculator.cs index e1ac234..503389d 100644 --- a/Runtime/Helper/GridLayoutCalculator.cs +++ b/Runtime/Helper/GridLayoutCalculator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; @@ -7,6 +7,7 @@ namespace XericUI.Helper public static class GridLayoutCalculator { public static Vector2 Grid; + public struct LayoutItem { public Vector2 position; // anchoredPosition @@ -53,6 +54,7 @@ namespace XericUI.Helper cellSize = new Vector2(Mathf.Max(0.1f, cellSize.x), Mathf.Max(0.1f, cellSize.y)); spacing = new Vector2(Mathf.Max(0f, spacing.x), Mathf.Max(0f, spacing.y)); + // todo 这里的行列数限制了实际行列数,需要修改计算扩容 // 1. 计算行列数 int cellCountX, cellCountY; CalculateGridDimensions(childCount, containerSize, cellSize, spacing, padding, @@ -64,7 +66,7 @@ namespace XericUI.Helper startAxis, out actualCellCountX, out actualCellCountY); Grid = new Vector2(actualCellCountX, actualCellCountY); - + // 3. 计算所需空间 Vector2 requiredSpace = new Vector2( actualCellCountX * cellSize.x + Mathf.Max(0, actualCellCountX - 1) * spacing.x, @@ -76,18 +78,18 @@ namespace XericUI.Helper requiredSpace, containerSize, padding, childAlignment, startCorner); // 5. 处理特殊情况 - - int childrenToMove = CalculateChildrenToMove(childCount, cellCountX, cellCountY, + + int childrenToMove = CalculateChildrenToMove(childCount, cellCountX, cellCountY, constraint, constraintCount, startAxis); // 6. 计算每个子项的位置 - int cornerX = (int)startCorner % 2; // 0=左, 1=右 - int cornerY = (int)startCorner / 2; // 0=上, 1=下 + int cornerX = (int)startCorner % 2; // 0=左, 1=右 + int cornerY = (int)startCorner / 2; // 0=上, 1=下 for (int i = 0; i < childCount; i++) { int gridX, gridY; - CalculateItemGridPosition(i, childCount, cellCountX, cellCountY, startAxis, + CalculateItemGridPosition(i, childCount, cellCountX, cellCountY, startAxis, constraint, constraintCount, childrenToMove, actualCellCountX, actualCellCountY, out gridX, out gridY); @@ -134,7 +136,7 @@ namespace XericUI.Helper } private static float CalculateAxisStartOffset( - int axis, // 0=X, 1=Y + int axis, // 0=X, 1=Y float requiredSpace, float availableSpace, RectOffset padding, @@ -143,28 +145,28 @@ namespace XericUI.Helper { // 计算包含padding的总需求空间 float requiredSpaceWithPadding = requiredSpace + (axis == 0 ? padding.horizontal : padding.vertical); - + // 计算剩余空间 float surplusSpace = availableSpace - requiredSpaceWithPadding; - + // 获取对齐值(0=左/上, 0.5=中, 1=右/下) float alignmentValue = GetAlignmentOnAxis(axis, childAlignment); - + // 关键:根据startCorner调整基准点 float baseOffset; - if (axis == 0) // X轴 + if (axis == 0) // X轴 { // 如果startCorner在右侧,基准点应该是availableSpace - padding.right - requiredSpace int cornerX = (int)startCorner % 2; baseOffset = (cornerX == 0) ? padding.left : (availableSpace - padding.right - requiredSpace); } - else // Y轴 + else // Y轴 { // 如果startCorner在底部,基准点应该是availableSpace - padding.bottom - requiredSpace int cornerY = (int)startCorner / 2; baseOffset = (cornerY == 0) ? padding.top : (availableSpace - padding.bottom - requiredSpace); } - + // 应用对齐(在剩余空间内) return baseOffset + surplusSpace * alignmentValue; } @@ -186,7 +188,7 @@ namespace XericUI.Helper // 计算基础位置(不考虑corner翻转) if (startAxis == GridLayoutGroup.Axis.Horizontal) { - if (constraint == GridLayoutGroup.Constraint.FixedRowCount && + if (constraint == GridLayoutGroup.Constraint.FixedRowCount && childrenToMove > 0 && childCount - index <= childrenToMove) { // 计算偏移量,确保gridY不会为负数 @@ -202,7 +204,7 @@ namespace XericUI.Helper } else { - if (constraint == GridLayoutGroup.Constraint.FixedColumnCount && + if (constraint == GridLayoutGroup.Constraint.FixedColumnCount && childrenToMove > 0 && childCount - index <= childrenToMove) { // 计算偏移量,确保gridX不会为负数 @@ -230,7 +232,7 @@ namespace XericUI.Helper return 0; int cellsPerMainAxis = startAxis == GridLayoutGroup.Axis.Horizontal ? cellCountX : cellCountY; - + if (cellsPerMainAxis <= 0) return 0; @@ -240,7 +242,7 @@ namespace XericUI.Helper int childrenToMove = constraintCount - (int)rowsNeeded; childrenToMove += Mathf.FloorToInt((float)childrenToMove / Mathf.Max(1f, (float)cellsPerMainAxis - 1)); - + if (childCount % cellsPerMainAxis == 1) childrenToMove += 1; @@ -262,34 +264,34 @@ namespace XericUI.Helper cellCountX = 1; cellCountY = 1; - if (constraint == GridLayoutGroup.Constraint.FixedColumnCount) + switch (constraint) { - cellCountX = constraintCount; - if (childCount > cellCountX) - cellCountY = childCount / cellCountX + (childCount % cellCountX > 0 ? 1 : 0); - } - else if (constraint == GridLayoutGroup.Constraint.FixedRowCount) - { - cellCountY = constraintCount; - if (childCount > cellCountY) - cellCountX = childCount / cellCountY + (childCount % cellCountY > 0 ? 1 : 0); - } - else - { - float availableWidth = containerSize.x - padding.horizontal; - float availableHeight = containerSize.y - padding.vertical; + case GridLayoutGroup.Constraint.FixedColumnCount: + cellCountX = constraintCount; + if (childCount > cellCountX) + cellCountY = childCount / cellCountX + (childCount % cellCountX > 0 ? 1 : 0); + break; + case GridLayoutGroup.Constraint.FixedRowCount: + cellCountY = constraintCount; + if (childCount > cellCountY) + cellCountX = childCount / cellCountY + (childCount % cellCountY > 0 ? 1 : 0); + break; + default: + float availableWidth = containerSize.x - padding.horizontal; + float availableHeight = containerSize.y - padding.vertical; - if (cellSize.x + spacing.x > 0) - cellCountX = Mathf.Max(1, - Mathf.FloorToInt((availableWidth + spacing.x + 0.001f) / (cellSize.x + spacing.x))); - else - cellCountX = int.MaxValue; + if (cellSize.x + spacing.x > 0) + cellCountX = Mathf.Max(1, + Mathf.FloorToInt((availableWidth + spacing.x + 0.001f) / (cellSize.x + spacing.x))); + else + cellCountX = int.MaxValue; - if (cellSize.y + spacing.y > 0) - cellCountY = Mathf.Max(1, - Mathf.FloorToInt((availableHeight + spacing.y + 0.001f) / (cellSize.y + spacing.y))); - else - cellCountY = int.MaxValue; + if (cellSize.y + spacing.y > 0) + cellCountY = Mathf.Max(1, + Mathf.FloorToInt((availableHeight + spacing.y + 0.001f) / (cellSize.y + spacing.y))); + else + cellCountY = int.MaxValue; + break; } } @@ -321,15 +323,14 @@ namespace XericUI.Helper else actualCellCountX = Mathf.Clamp(cellCountX, 1, Mathf.CeilToInt(childCount / (float)cellCountY)); } - } private static float GetAlignmentOnAxis(int axis, TextAnchor childAlignment) { if (axis == 0) - return ((int)childAlignment % 3) * (1f / 3f); // 0, 0.333, 0.666 + return ((int)childAlignment % 3) * (1f / 3f); // 0, 0.333, 0.666 else - return ((int)childAlignment / 3) * 0.5f; // 0, 0.5, 1 + return ((int)childAlignment / 3) * 0.5f; // 0, 0.5, 1 } } } \ No newline at end of file diff --git a/Runtime/Helper/UIVesselHelp.cs b/Runtime/Helper/UIVesselHelp.cs index 8308037..c50cd40 100644 --- a/Runtime/Helper/UIVesselHelp.cs +++ b/Runtime/Helper/UIVesselHelp.cs @@ -4,15 +4,15 @@ namespace XericUI.Helper { public static class UIVesselHelper { - public static void CallVisibal(this IUIVesselVisibalControl control, bool underVisible) + public static void CallVisible(this IUIVesselVisibalControl control, bool underVisible) { if (underVisible) { - control.UnderVisibal(); + control.UnderVisible(); } else { - control.OutOfVisibal(); + control.OutOfVisible(); } } } diff --git a/Runtime/OverrideLayout/XericScrollRect.cs b/Runtime/OverrideLayout/XericScrollRect.cs index 6dd1a33..8c82b51 100644 --- a/Runtime/OverrideLayout/XericScrollRect.cs +++ b/Runtime/OverrideLayout/XericScrollRect.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using UnityEngine.Pool; using UnityEngine.Serialization; using UnityEngine.UI; +using XericLibrary.Runtime.Debuger; using XericLibrary.Runtime.MacroLibrary; using XericUI.Core.Interface; using XericUI.Helper; @@ -27,8 +29,7 @@ namespace XericUI.OverrideLayout { #region 字段属性 - [Tooltip("启用自动剔除功能")] [SerializeField] - protected bool m_enableAdvancedFunc = true; + [Tooltip("启用自动剔除功能")] [SerializeField] protected bool m_enableAdvancedFunc = true; [Tooltip("容器预加载像素范围")] [SerializeField] protected float m_preloadMargin = 200f; @@ -46,7 +47,11 @@ namespace XericUI.OverrideLayout [SerializeField] protected GridLayoutGroup.Corner m_startCorner = GridLayoutGroup.Corner.UpperLeft; [SerializeField] protected GridLayoutGroup.Axis m_startAxis = GridLayoutGroup.Axis.Horizontal; [SerializeField] protected TextAnchor m_childAlignment = TextAnchor.UpperLeft; - [SerializeField] protected GridLayoutGroup.Constraint m_constraint = GridLayoutGroup.Constraint.Flexible; + + [SerializeField] + protected GridLayoutGroup.Constraint m_constraint = GridLayoutGroup.Constraint.FixedColumnCount; + + [SerializeField] protected int m_constraintCount = -1; /// /// 对象池 @@ -67,7 +72,7 @@ namespace XericUI.OverrideLayout UpdateContentLayout(1, value.y); } } - + #endregion #region 布局参考 @@ -80,13 +85,16 @@ namespace XericUI.OverrideLayout private Vector2 _lastContextAnchoredPosition; private List _layoutItems; - + private Queue _activeQueue = new Queue(); private bool layoutHasRebuildAtThisFrame; private bool layoutDirty; private bool indexMapDirty; - + + private Vector2 visibleMin; + private Vector2 visibleMax; + #endregion [Serializable] @@ -95,30 +103,55 @@ namespace XericUI.OverrideLayout public GridLayoutCalculator.LayoutItem layout; public int index { get; internal set; } protected internal XericScrollRect parentScrollRect; - private bool _uiVisibal; + protected bool _uiVisibal; protected GameObject item; public RectTransform itemRectTransform => item ? item.RectTransform() : null; - public IUIVesselVisibalControl ItemUIVesselVisibalControlComponent => item ? itemRectTransform.GetComponent() : null; + + /// + /// 滚动框如何定位到接口(此接口返回的对象将用于生命周期管理,否则退化成简单的组件显影) + /// + public virtual IUIVesselVisibalControl ItemUIVesselVisibalControlComponent => this; + public bool GetUIVisibal => _uiVisibal; - public virtual void UnderVisibal() + public virtual void UnderVisible() { + SetIsVisible(true); item = parentScrollRect.childrenPool.Get(); - parentScrollRect.UpdateChildPivot(layout, item.RectTransform()); - itemRectTransform.anchoredPosition = layout.position; + RefreshPivot(); } - public virtual void OutOfVisibal() - { + public virtual void OutOfVisible() + { + SetIsVisible(false); parentScrollRect.childrenPool.DirectlyRelease(item); item = null; } + protected void SetIsVisible(bool visible) + { + _uiVisibal = visible; + } + + protected void RefreshPivot() + { + if (!item) + { + Debug.LogError($"滚动视图的实体对象在刷新前并未指定,请先指定{nameof(item)}后再调用{nameof(RefreshPivot)}"); + } + + parentScrollRect.UpdateChildPivot(layout, item.RectTransform()); + itemRectTransform.anchoredPosition = layout.position; + } + public void UpdateLayout(GridLayoutCalculator.LayoutItem layoutData) { layout = layoutData; } + + public Vector2 WorldAnchoredPosition(RectTransform parentContent) + => parentContent.TransformPoint(itemRectTransform.anchoredPosition); } #region 生命周期 @@ -127,6 +160,7 @@ namespace XericUI.OverrideLayout private Vector3[] vertex1 = new Vector3[4]; private Vector3[] vertex2 = new Vector3[4]; private Vector3[] vertex3 = new Vector3[4]; + private void OnDrawGizmosSelected() { var lossyScale = transform.lossyScale; @@ -157,6 +191,29 @@ namespace XericUI.OverrideLayout MacroGizmosDraw.DrawGizmos2RectLinkCube(vertex3, vertex1, Color.cyan, Color.red, true); MacroGizmosDraw.Label(vertex3[1], "preload Rect"); MacroGizmosDraw.Label(vertex1[1], "display Rect"); + + if (!Application.isPlaying) return; + + Gizmos.color = Color.magenta; + MacroGizmosDraw.DrawGizmosRectLine(visibleMin - Vector2.one, visibleMax - Vector2.one); + + var corners = new Vector3[4]; + foreach (var data in _childrenDatas) + { + if (data.GetUIVisibal) + { + Gizmos.color = Color.green; + data.itemRectTransform.GetWorldCorners(corners); + MacroGizmosDraw.DrawPolygonLineByPointArray(corners); + MacroGizmosDraw.Label(corners[0], $"[{data.index}] 使用中"); + } + else + { + Gizmos.color = Color.red; + MacroGizmosDraw.DrawGizmosRectAtPoint(data.layout.position, data.layout.size); + MacroGizmosDraw.Label(data.layout.position, $"[{data.index}] 已回收"); + } + } } protected override void OnValidate() @@ -221,16 +278,6 @@ namespace XericUI.OverrideLayout protected override void LateUpdate() { layoutHasRebuildAtThisFrame = false; - base.LateUpdate(); - // 布局刷新 - if (layoutDirty) - { - layoutDirty = false; - // 常规的刷新依赖视图的更新,如果这一帧只增删了对象,但是视图没有移动,那么这里就会执行更新 - if (layoutHasRebuildAtThisFrame) - UpdateAAMVSVisibleStatus(); - RefreshLayout(); - } // 全部索引刷新 if (indexMapDirty) { @@ -238,6 +285,19 @@ namespace XericUI.OverrideLayout for (int i = 0; i < _childrenDatas.Count; i++) _childrenDatas[i].index = i; } + + // 重新计算布局 + if (layoutDirty) + RefreshLayout(); + base.LateUpdate(); + // 布局刷新 + if (layoutDirty) + { + layoutDirty = false; + // 常规的刷新依赖视图的更新,如果这一帧只增删了对象,但是视图没有移动,那么这里就会执行更新 + if (!layoutHasRebuildAtThisFrame) + UpdateAAMVSVisibleStatus(); + } } private Vector3[] viewportVertex = new Vector3[4]; @@ -252,16 +312,17 @@ namespace XericUI.OverrideLayout // 手动计算视口在content空间的矩形 viewport.GetWorldCorners(viewportVertex); var viewportRect = new Rect( - content.InverseTransformPoint(viewportVertex[0]), - content.InverseTransformPoint(viewportVertex[2]) - content.InverseTransformPoint(viewportVertex[0])); + viewportVertex[0], + viewportVertex[2] - viewportVertex[0]); var contentRect = content.rect; // 计算预加载边距(考虑content缩放) // var scaledMargin = preloadMargin / ((content.lossyScale.x + content.lossyScale.y) * 0.5f); // 扩展可见区域边界 - var visibleMin = viewportRect.min - new Vector2(m_preloadMargin, m_preloadMargin); - var visibleMax = viewportRect.max + new Vector2(m_preloadMargin, -m_preloadMargin); + var preloadMarginVec2 = new Vector2(m_preloadMargin, m_preloadMargin); + visibleMin = viewportRect.min - preloadMarginVec2; + visibleMax = viewportRect.max + preloadMarginVec2; // 获取当前滚动归一化位置 // var scrollPos = new Vector2( @@ -275,9 +336,9 @@ namespace XericUI.OverrideLayout { var visControl = childData.ItemUIVesselVisibalControlComponent; var isVisControlValid = visControl != null; - + // 直接使用anchoredPosition进行边界检测 - var childPos = childRectTransform.anchoredPosition; + var childPos = childData.WorldAnchoredPosition(content); var isVisible = CheckIsVisibal(childPos); var nowActive = childRectTransform.GetActivity(); @@ -291,23 +352,20 @@ namespace XericUI.OverrideLayout // 向成员发送状态(如果成员没有实现接口,就直接通过可见性控制) if (isVisControlValid) - visControl.CallVisibal(isVisible); + visControl.CallVisible(isVisible); else childRectTransform.gameObject.SetActive(isVisible); } else { - var isVisible = CheckIsVisibal(childData.layout.position); - if (isVisible) - { - childData.UnderVisibal(); - } - } + if (!CheckIsVisibal(childData.layout.position)) + childData.UnderVisible(); + } } - + bool CheckIsVisibal(Vector2 pos) { - return + return pos.x >= visibleMin.x && pos.x <= visibleMax.x && pos.y >= visibleMin.y && @@ -315,8 +373,6 @@ namespace XericUI.OverrideLayout } } - - #endregion #region 数据管理 @@ -324,13 +380,34 @@ namespace XericUI.OverrideLayout /// /// 添加一个子项(自行重写这个子项类型数据结构,基于其中的生命周期函数完成内容的更新) /// - /// - public void AddChildData(ScrollItemData Data) + /// + public void AddChildData(ScrollItemData data) { layoutDirty = true; - Data.index = _childrenDatas.Count; - Data.parentScrollRect = this; - _childrenDatas.Add(Data); + data.index = _childrenDatas.Count; + data.parentScrollRect = this; + _childrenDatas.Add(data); + } + + /// + /// 添加一个子项在倒序的多少项之前 + /// + /// + /// 指定这个项目插入在倒序的第几位 + /// + /// 比如一个视图中有不同的几种对象,如常规对象和新建对象按钮,将这个对象插入在新建对象之前 + /// + public void AddChildData(ScrollItemData data, int invertedOrder) + { + layoutDirty = true; + indexMapDirty = true; + data.parentScrollRect = this; + + var insertIndex = _childrenDatas.Count - invertedOrder; + insertIndex = Mathf.Clamp(insertIndex, 0, _childrenDatas.Count); + _childrenDatas.Insert(insertIndex, data); + // for (int i = 0; i < _childrenDatas.Count; i++) + // _childrenDatas[i].index = i; } public void RemoveChildData(int index) @@ -339,7 +416,7 @@ namespace XericUI.OverrideLayout indexMapDirty = true; // 如果可见,先移除可见性 if (_childrenDatas[index].GetUIVisibal) - _childrenDatas[index].OutOfVisibal(); + _childrenDatas[index].OutOfVisible(); _childrenDatas.RemoveAt(index); } @@ -349,7 +426,7 @@ namespace XericUI.OverrideLayout indexMapDirty = true; // 如果可见,先移除可见性 if (index.GetUIVisibal) - index.OutOfVisibal(); + index.OutOfVisible(); _childrenDatas.Remove(index); } @@ -360,10 +437,10 @@ namespace XericUI.OverrideLayout // 如果可见,先移除可见性 foreach (var data in _childrenDatas) if (data.GetUIVisibal) - data.OutOfVisibal(); + data.OutOfVisible(); _childrenDatas.Clear(); } - + public ScrollItemData GetChildData(int index) { return _childrenDatas[index]; @@ -375,18 +452,28 @@ namespace XericUI.OverrideLayout private void RefreshLayout() { - var layouts = GetChildrenLayout(content.transform.childCount); + Debug.Log("刷新"); + var layouts = GetChildrenLayout(_childrenDatas.Count); for (int i = 0; i < layouts.Count; i++) { - var trans = content.transform.GetChild(i) as RectTransform; - UpdateChildPivot(layouts[i], trans); - trans.anchoredPosition = layouts[i].position; - trans.SetDeltaSize(m_cellSize); + var childData = _childrenDatas[i]; + childData.UpdateLayout(layouts[i]); + + var trans = childData.itemRectTransform; + if (trans) + { + UpdateChildPivot(layouts[i], trans); // 先更新枢轴 + if (trans != null) + { + trans.anchoredPosition = layouts[i].position; + trans.SetDeltaSize(m_cellSize); + } + } } RefreshContentSizeByChildrenLayouts(layouts); } - + private void UpdateContentLayout(int axis, float overrideSize) { content.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, overrideSize); @@ -398,24 +485,25 @@ namespace XericUI.OverrideLayout private void RefreshContentSizeByChildrenLayouts(List layoutItems) { if (layoutItems.Count == 0) return; - + var first = layoutItems[0]; var last = layoutItems[^1]; var size = first.position - last.position; size = size.Abs(); - + // 计算实际使用的行列数 - int maxRow = 0; - int maxColumn = 0; + int maxRow = (int)GridLayoutCalculator.Grid.x; + int maxColumn = (int)GridLayoutCalculator.Grid.y; foreach (var item in layoutItems) { maxRow = Mathf.Max(maxRow, item.rowIndex); maxColumn = Mathf.Max(maxColumn, item.columnIndex); } + int actualCellCountX = maxColumn + 1; int actualCellCountY = maxRow + 1; - + var spacing = new Vector2((actualCellCountX - 1) * m_spacing.x, (actualCellCountY - 1) * m_spacing.y); switch (m_startAxis) { @@ -425,9 +513,10 @@ namespace XericUI.OverrideLayout break; case GridLayoutGroup.Axis.Vertical: size.x = Mathf.Max(size.x + m_spacing.x, m_cellSize.x); - size.y = Mathf.Max(size.y, viewport.rect.height); + size.y = Mathf.Max(size.y, viewport.rect.height); break; } + ContextSize = size; } @@ -437,7 +526,7 @@ namespace XericUI.OverrideLayout { // todo 对齐算法总的方向应该是写错了,找找 GridLayoutGroup.Corner.UpperLeft => new Vector2(0, 1), - GridLayoutGroup.Corner.UpperRight => new Vector2(1, 1), + GridLayoutGroup.Corner.UpperRight => new Vector2(1, 1), GridLayoutGroup.Corner.LowerLeft => new Vector2(0, 0), GridLayoutGroup.Corner.LowerRight => new Vector2(1, 0), _ => throw new ArgumentOutOfRangeException() @@ -461,21 +550,23 @@ namespace XericUI.OverrideLayout { var first = layoutItems[0]; var last = layoutItems[^1]; - + // first.position } - + private List GetChildrenLayout(int childrenCount) { // 根据约束类型设置合适的 constraintCount - int constraintCount = 0; - if (m_constraint == GridLayoutGroup.Constraint.FixedColumnCount || m_constraint == GridLayoutGroup.Constraint.FixedRowCount) + int constraintCount = m_constraint switch { - // 这里可以根据实际需求设置合适的约束数量 - // 暂时使用一个默认值,实际项目中可能需要从外部传入或通过其他方式计算 - constraintCount = 3; - } - + GridLayoutGroup.Constraint.FixedColumnCount => Mathf.CeilToInt(m_cellSize.x / ContextSize.x), + GridLayoutGroup.Constraint.FixedRowCount => Mathf.CeilToInt(m_cellSize.y / ContextSize.y), + _ => 0, + }; + + if (m_constraintCount > 0) + constraintCount = m_constraintCount; + return GridLayoutCalculator.CalculateGridLayout( _layoutItems, childCount: childrenCount,