124 lines
4.1 KiB
C#
124 lines
4.1 KiB
C#
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>();
|
||
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<RectTransform>();
|
||
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<TMPro.TextMeshProUGUI>();
|
||
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<Text>();
|
||
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);
|
||
}
|
||
}
|
||
}
|