HKMBFZ/Assets/Scripts/Szz_Scripts/UI/122/炮长/KeyboardScrollView.cs

164 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class KeyboardScrollView : MonoBehaviour
{
[Header("Scroll View 组件")]
public ScrollRect scrollRect;
public RectTransform content;
[Header("Item 列表")]
private List<GameObject> items = new List<GameObject>();
private int currentIndex = 0;
public UnityEvent<string> enterEvent;
void Start()
{
// 自动收集 Content 下的所有直接子物体作为 item
items.Clear();
foreach (Transform child in content)
{
items.Add(child.gameObject);
}
// 禁止鼠标滚轮
scrollRect.scrollSensitivity = 0;
// 禁止鼠标拖动
CanvasGroup cg = scrollRect.GetComponent<CanvasGroup>();
if (cg == null) cg = scrollRect.gameObject.AddComponent<CanvasGroup>();
cg.interactable = false;
// 初始化:关闭所有 select打开第一个
foreach (GameObject item in items)
{
Transform select = item.transform.GetChild(0);
if (select != null)
select.gameObject.SetActive(false);
}
currentIndex = 0;
currectSelect = items[0];
UpdateSelection();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.DownArrow))
{
MoveNext();
}
else if (Input.GetKeyDown(KeyCode.UpArrow))
{
MovePrevious();
}
if (Input.GetKeyDown(KeyCode.Return))
{
if (currectSelect.name.Split('-').Length == 1)
return;
enterEvent?.Invoke(currectSelect.name.Split('-')[1]); //有些按钮会通向同一个页面
}
}
void MoveNext()
{
if (currentIndex < items.Count - 1)
{
currentIndex++;
UpdateSelection();
ScrollIfNeeded();
currectSelect = items[currentIndex];
}
}
void MovePrevious()
{
if (currentIndex > 0)
{
currentIndex--;
UpdateSelection();
ScrollIfNeeded();
currectSelect = items[currentIndex];
}
}
private GameObject currectSelect;
void UpdateSelection()
{
for (int i = 0; i < items.Count; i++)
{
Transform select = items[i].transform.GetChild(0);
if (select != null)
{
select.gameObject.SetActive(i == currentIndex);
}
}
}
void ScrollIfNeeded()
{
// 强制刷新布局
LayoutRebuilder.ForceRebuildLayoutImmediate(content);
RectTransform selectedItem = items[currentIndex].GetComponent<RectTransform>();
// 将 item 的四个角转换到 viewport 坐标系
Vector3[] itemWorldCorners = new Vector3[4];
selectedItem.GetWorldCorners(itemWorldCorners);
Vector3[] viewportWorldCorners = new Vector3[4];
scrollRect.viewport.GetWorldCorners(viewportWorldCorners);
float itemTop = itemWorldCorners[1].y; // 左上角 y
float itemBottom = itemWorldCorners[0].y; // 左下角 y
float viewportTop = viewportWorldCorners[1].y;
float viewportBottom = viewportWorldCorners[0].y;
float delta = 0f;
// item 顶部高于 viewport 顶部,向下滚动
if (itemTop > viewportTop)
{
delta = itemTop - viewportTop;
content.anchoredPosition -= new Vector2(0, delta);
}
// item 底部低于 viewport 底部,向上滚动
else if (itemBottom < viewportBottom)
{
delta = viewportBottom - itemBottom;
content.anchoredPosition += new Vector2(0, delta);
}
// 限制滚动范围
float maxY = Mathf.Max(0, content.rect.height - scrollRect.viewport.rect.height);
float y = Mathf.Clamp(content.anchoredPosition.y, 0, maxY);
content.anchoredPosition = new Vector2(content.anchoredPosition.x, y);
}
// 获取当前可视区域的第一个 item 索引
int GetFirstVisibleIndex()
{
float scrollTop = content.anchoredPosition.y;
for (int i = 0; i < items.Count; i++)
{
RectTransform item = items[i].GetComponent<RectTransform>();
float itemTop = Mathf.Abs(item.anchoredPosition.y);
float itemBottom = itemTop + item.rect.height;
if (itemBottom > scrollTop)
{
return i;
}
}
return 0;
}
}