using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System.Collections; using Logic.CrashSight; namespace UI.Common { [RequireComponent(typeof(ScrollRect))] public class ChooseUISnapScrollRect : MonoBehaviour, IEndDragHandler { public RectTransform content; // 自动寻找 Viewport/List public float snapSpeed = 10f; // 平滑速度 public float snapThreshold = 0.1f; // 靠近这个范围就停止 public float itemHeight = 60f; // 每项高度(固定) private ScrollRect scrollRect; private bool isSnapping = false; private int itemCount = 0; public int selectedIndex = -1; void Start() { scrollRect = GetComponent(); scrollRect.horizontal = false; scrollRect.vertical = true; // 自动寻找 Viewport/List if (content == null) { Transform viewport = transform.Find("Viewport"); if (viewport != null) { Transform list = viewport.Find("List"); if (list != null) { content = list.GetComponent(); scrollRect.content = content; } else { LogSystem.LogError($"{name}: 找不到 Viewport/List!"); } } else { LogSystem.LogError($"{name}: 找不到 Viewport!"); } } if (content != null) { itemCount = content.childCount; } } public void OnEndDrag(PointerEventData eventData) { if (!isSnapping && content != null) { StartCoroutine(SnapToClosestItem()); } } IEnumerator SnapToClosestItem() { isSnapping = true; float currentY = content.anchoredPosition.y; int closestIndex = Mathf.RoundToInt(currentY / itemHeight); closestIndex = Mathf.Clamp(closestIndex, 0, itemCount - 1); selectedIndex = closestIndex; float targetY = closestIndex * itemHeight; while (Mathf.Abs(content.anchoredPosition.y - targetY) > snapThreshold) { float newY = Mathf.Lerp(content.anchoredPosition.y, targetY, Time.deltaTime * snapSpeed); content.anchoredPosition = new Vector2(content.anchoredPosition.x, newY); yield return null; } content.anchoredPosition = new Vector2(content.anchoredPosition.x, targetY); HighlightSelectedItem(closestIndex); isSnapping = false; } private void HighlightSelectedItem(int selected) { for (int i = 0; i < itemCount; i++) { var option = content.GetChild(i); var tmp = option.GetComponent(); if (tmp != null) { tmp.color = (i == selected) ? new Color32(0xFF, 0xFF, 0xFF, 255) // #FFFFFF : new Color32(0x78, 0x78, 0x78, 255); // #787878 continue; } var uiText = option.GetComponent(); if (uiText != null) { uiText.color = (i == selected) ? new Color32(0xFF, 0xFF, 0xFF, 255) : new Color32(0x78, 0x78, 0x78, 255); } } } // 可手动吸附到某一项 public void SnapToIndex(int index) { index = Mathf.Clamp(index, 0, itemCount - 1); float targetY = index * itemHeight; content.anchoredPosition = new Vector2(content.anchoredPosition.x, targetY); selectedIndex = index; HighlightSelectedItem(index); } } }