hch
2 天以前 cd759dfd81f421dc64858ceef367564609634ae6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using UnityEngine;
using System.Collections.Generic;
 
[ExecuteAlways]
[RequireComponent(typeof(RectTransform))]
public class HomeGridLayout : MonoBehaviour
{
    public RectOffset padding = new RectOffset();      // 边距
    public Vector2 cellSize = new Vector2(100f, 100f); // 单元格大小
    public Vector2 spacing = new Vector2(10f, 10f);    // 元素间距
    public int rows = 7; // 固定行数
 
    private void OnRectTransformDimensionsChange() => UpdateLayout();
    private void OnTransformChildrenChanged() => UpdateLayout();
 
#if UNITY_EDITOR
    private void Update()
    {
        if (!Application.isPlaying) UpdateLayout();
    }
#endif
 
    public void UpdateLayout()
    {
        if (rows <= 0 || transform.childCount == 0) return;
 
        List<RectTransform> flowChildren = new List<RectTransform>();
        List<RectTransform> fixedChildren = new List<RectTransform>();
 
        // 1. 遍历收集并分类所有激活的子物体
        for (int i = 0; i < transform.childCount; i++)
        {
            RectTransform child = transform.GetChild(i) as RectTransform;
            if (child == null || !child.gameObject.activeSelf) continue;
 
            HomeGridLayoutCell cell = child.GetComponent<HomeGridLayoutCell>();
            
            if (cell != null && cell.isFixedPosition)
                fixedChildren.Add(child);
            else
                flowChildren.Add(child);
        }
 
        // 2. 排序流动物体 (按 sortIndex)
        flowChildren.Sort((a, b) =>
        {
            var cellA = a.GetComponent<HomeGridLayoutCell>();
            var cellB = b.GetComponent<HomeGridLayoutCell>();
            int indexA = cellA != null ? cellA.sortIndex : int.MaxValue;
            int indexB = cellB != null ? cellB.sortIndex : int.MaxValue;
            return indexA.CompareTo(indexB);
        });
 
        // 3. 排序固定物体 (优先 sortIndex,其次 subSortIndex)
        fixedChildren.Sort((a, b) =>
        {
            var cellA = a.GetComponent<HomeGridLayoutCell>();
            var cellB = b.GetComponent<HomeGridLayoutCell>();
            
            int sortA = cellA != null ? cellA.sortIndex : int.MaxValue;
            int sortB = cellB != null ? cellB.sortIndex : int.MaxValue;
            
            if (sortA != sortB) return sortA.CompareTo(sortB);
 
            int subA = cellA != null ? cellA.subSortIndex : int.MaxValue;
            int subB = cellB != null ? cellB.subSortIndex : int.MaxValue;
            return subA.CompareTo(subB);
        });
 
        // 4. 开始分配网格 (核心优化部分)
        int currentGridIndex = 0; // 当前推演到的真实网格坑位
        int flowIndex = 0;
        int fixedIndex = 0;
        int totalValidChildren = flowChildren.Count + fixedChildren.Count;
 
        for (int i = 0; i < totalValidChildren; i++)
        {
            RectTransform targetChild = null;
            HomeGridLayoutCell nextFixedCell = null;
 
            if (fixedIndex < fixedChildren.Count)
            {
                nextFixedCell = fixedChildren[fixedIndex].GetComponent<HomeGridLayoutCell>();
            }
 
            // 分支 A:固定物体已经到了它期望的网格位置(或已经被前面的元素挤到了当前位置)
            if (nextFixedCell != null && nextFixedCell.sortIndex <= currentGridIndex)
            {
                targetChild = fixedChildren[fixedIndex];
                fixedIndex++;
            }
            // 分支 B:当前位置没有固定物体抢占,且还有流动物体排队,让流动物体填补空缺
            else if (flowIndex < flowChildren.Count)
            {
                targetChild = flowChildren[flowIndex];
                flowIndex++;
            }
            // 分支 C:没有流动物体填补空缺了,直接让网格索引“快进”到下一个固定物体的位置
            else if (nextFixedCell != null)
            {
                currentGridIndex = nextFixedCell.sortIndex; // 快进跳过中间的所有空白格子
                targetChild = fixedChildren[fixedIndex];
                fixedIndex++;
            }
 
            // 应用计算好的网格坐标
            if (targetChild != null)
            {
                SetChildTransform(targetChild, currentGridIndex);
                currentGridIndex++; // 占位成功,坑位后移
            }
        }
    }
 
   /// <summary>
    /// 将子物体放置到指定的网格索引位置
    /// </summary>
    private void SetChildTransform(RectTransform child, int gridIndex)
    {
        int col = gridIndex / rows;
        int row = gridIndex % rows;
 
        // 1. 先计算出如果轴心在右上角时的理论边缘坐标
        float edgeXPos = -padding.right - col * (cellSize.x + spacing.x);
        float edgeYPos = -padding.top - row * (cellSize.y + spacing.y);
 
        // 2. 为了消除团队潜规则,我们将格子的轴心改回正中心 (0.5, 0.5)
        // 因此实际坐标需要向左、向下再偏移半个单元格的大小
        float centerXPos = edgeXPos - (cellSize.x * 0.5f);
        float centerYPos = edgeYPos - (cellSize.y * 0.5f);
 
        // 统一锚点为右上角 (1, 1)
        child.anchorMin = new Vector2(1, 1);
        child.anchorMax = new Vector2(1, 1);
        
        // 轴心(Pivot)改为正中心!
        child.pivot = new Vector2(0.5f, 0.5f); 
        
        child.sizeDelta = cellSize;
        
        // 赋予中心坐标
        child.anchoredPosition = new Vector2(centerXPos, centerYPos);
    }
}