为什么 Codex 搭载 GPT-5.6 后,越来越多用户开始弃用 Skills?
2026/8/13 14:01:26
判断Item在Scrollview列表的上下左右,直接挂就行
using System; using System.Collections.Generic; using UnityEngine; /// <summary> /// 在滚动列表中查找"可激活"Item相对视口的位置(上方 / 下方 / 视口内 / 无), /// 并计算跳转按钮应显示在左侧还是右侧。 /// /// 使用方式: /// 1. 挂载到任意 GameObject 上,或通过 AddComponent 动态挂载。 /// 2. 设置 ScrollContainer(滚动视口的 RectTransform)和 ShowXPos。 /// 3. 每帧或滚动时调用 Locate(),根据返回值刷新按钮显示。 /// </summary> public class ScrollActiveItemLocator : MonoBehaviour { // --------------------------------------------------------------- // 枚举 // --------------------------------------------------------------- public enum State { None, MiddleActive, // 可激活 Item 在视口内 UpActive, // 可激活 Item 在视口上方(需要向上滚动) DownActive, // 可激活 Item 在视口下方(需要向下滚动) } // --------------------------------------------------------------- // 数据结构(调用方填充后传入) // --------------------------------------------------------------- /// <summary>当前视口中已渲染出来的 Item 信息</summary> public struct VisibleItem { /// <summary>该 Item 在全量数据列表中的索引</summary> public int Index; /// <summary>用于判断是否在视口内的 RectTransform</summary> public RectTransform Rect; /// <summary>该 Item 当前是否处于"可激活"状态</summary> public bool IsCanActive; } /// <summary>全量数据列表中每条数据的状态(无需 RectTransform)</summary> public struct DataItem { public bool IsCanActive; } // --------------------------------------------------------------- // 公开配置 // --------------------------------------------------------------- [Tooltip("滚动视口的 RectTransform,用于判断 Item 是否在可见区域内")] public RectTransform ScrollContainer; [Tooltip("跳转按钮的 X 轴偏移量,正值=右侧,负值=左侧")] public float ShowXPos = 150f; // --------------------------------------------------------------- // 核心方法 // --------------------------------------------------------------- /// <summary> /// 根据当前可见 Item 列表和全量数据,找出最近的"可激活" Item 的位置。 /// </summary> /// <param name="visibleItems">Loop 列表当前渲染出的所有 Item(含视口外的缓存行)</param> /// <param name="allDataItems">完整数据列表,用于在视口外扫描</param> /// <param name="activeIndex">找到的可激活 Item 在 allDataItems 中的索引</param> /// <param name="buttonPosX">跳转按钮应使用的 X 坐标(根据列数奇偶判断左右)</param> /// <returns>当前定位状态</returns> public State Locate( IList<VisibleItem> visibleItems, IList<DataItem> allDataItems, out int activeIndex, out float buttonPosX) { int minVisibleIndex = int.MaxValue; int maxVisibleIndex = int.MinValue; // 先在视口内找 foreach (var item in visibleItems) { if (!IsInScrollRect(item.Rect)) continue; if (item.IsCanActive) { activeIndex = item.Index; buttonPosX = GetButtonPosX(item.Index); return State.MiddleActive; } if (item.Index < minVisibleIndex) minVisibleIndex = item.Index; if (item.Index > maxVisibleIndex) maxVisibleIndex = item.Index; } // 视口上方扫描(从最小可见索引往前) if (minVisibleIndex > 0) { for (int i = minVisibleIndex; i >= 0; i--) { if (allDataItems[i].IsCanActive) { activeIndex = i; buttonPosX = GetButtonPosX(i); return State.UpActive; } } } // 视口下方扫描(从最大可见索引往后) if (maxVisibleIndex > 0) { for (int i = maxVisibleIndex; i < allDataItems.Count; i++) { if (allDataItems[i].IsCanActive) { activeIndex = i; buttonPosX = GetButtonPosX(i); return State.DownActive; } } } activeIndex = 0; buttonPosX = 0f; return State.None; } // --------------------------------------------------------------- // 辅助方法 // --------------------------------------------------------------- /// <summary> /// 判断 itemRect 是否(至少有一个角点)在 ScrollContainer 的世界空间矩形内。 /// </summary> public bool IsInScrollRect(RectTransform itemRect) { if (ScrollContainer == null || itemRect == null) return false; Vector3[] containerCorners = new Vector3[4]; Vector3[] itemCorners = new Vector3[4]; ScrollContainer.GetWorldCorners(containerCorners); itemRect.GetWorldCorners(itemCorners); // GetWorldCorners 返回顺序:左下(0)、左上(1)、右上(2)、右下(3) Rect containerRect = new Rect( containerCorners[0], containerCorners[2] - containerCorners[0]); for (int i = 0; i < 4; i++) { if (containerRect.Contains(itemCorners[i])) return true; } return false; } /// <summary> /// 根据 Item 索引的奇偶性决定按钮显示在左侧还是右侧。 /// 偶数索引 → 左列 → 负 X;奇数索引 → 右列 → 正 X。 /// </summary> private float GetButtonPosX(int index) { return index % 2 == 0 ? -ShowXPos : ShowXPos; } }