DCS/ruiyiweiUX/Assets/Scripts/UI/TabNavigationSystem.cs

369 lines
9.7 KiB
C#
Raw Permalink 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 TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// Tab键导航系统
/// 自动管理InputField之间的Tab键切换
/// </summary>
public class TabNavigationSystem : MonoBehaviour
{
[Header("导航设置")]
public List<Selectable> NavigationOrder = new List<Selectable>(); // 导航顺序
public bool AutoDetectInputFields = true; // 自动检测InputField
public bool WrapNavigation = true; // 是否循环导航
public bool EnableShiftReverse = true; // 是否支持Shift+Tab反向导航
[Header("调试")]
public bool ShowDebugInfo = false;
private int _currentIndex = -1;
private EventSystem _eventSystem;
void Start()
{
Initialize();
}
void Update()
{
HandleTabInput();
}
private void Initialize()
{
_eventSystem = EventSystem.current;
if (AutoDetectInputFields)
{
AutoDetectNavigationElements();
}
// 设置初始焦点
if (NavigationOrder.Count > 0)
{
SetFocus(0);
}
if (ShowDebugInfo)
{
Debug.Log($"TabNavigationSystem: 初始化完成,找到 {NavigationOrder.Count} 个可导航元素");
}
}
/// <summary>
/// 自动检测可导航元素
/// </summary>
private void AutoDetectNavigationElements()
{
NavigationOrder.Clear();
// 查找所有InputField
var inputFields = FindObjectsOfType<TMP_InputField>();
foreach (var inputField in inputFields)
{
if (inputField.interactable && inputField.gameObject.activeInHierarchy)
{
NavigationOrder.Add(inputField);
}
}
// 查找所有传统InputField
var legacyInputFields = FindObjectsOfType<InputField>();
foreach (var inputField in legacyInputFields)
{
if (inputField.interactable && inputField.gameObject.activeInHierarchy)
{
NavigationOrder.Add(inputField);
}
}
// 根据层级顺序排序
NavigationOrder.Sort((a, b) =>
{
// 先按Y坐标排序从上到下
var posA = a.transform.position;
var posB = b.transform.position;
if (Mathf.Abs(posA.y - posB.y) > 0.1f)
{
return posB.y.CompareTo(posA.y); // Y坐标大的在前上面的先
}
// Y坐标相近时按X坐标排序从左到右
return posA.x.CompareTo(posB.x);
});
}
/// <summary>
/// 处理Tab键输入
/// </summary>
private void HandleTabInput()
{
if (NavigationOrder.Count == 0) return;
// 检查Tab键
if (Input.GetKeyDown(KeyCode.Tab))
{
bool reverse = EnableShiftReverse && (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift));
if (reverse)
{
NavigatePrevious();
}
else
{
NavigateNext();
}
}
// 检查Enter键移动到下一个
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
{
// 如果当前焦点是InputField则移动到下一个
var currentSelection = _eventSystem?.currentSelectedGameObject;
if (currentSelection != null)
{
var inputField = currentSelection.GetComponent<TMP_InputField>();
var legacyInputField = currentSelection.GetComponent<InputField>();
if (inputField != null || legacyInputField != null)
{
NavigateNext();
}
}
}
}
/// <summary>
/// 导航到下一个元素
/// </summary>
public void NavigateNext()
{
if (NavigationOrder.Count == 0) return;
_currentIndex++;
if (WrapNavigation)
{
_currentIndex %= NavigationOrder.Count;
}
else
{
_currentIndex = Mathf.Min(_currentIndex, NavigationOrder.Count - 1);
}
SetFocus(_currentIndex);
}
/// <summary>
/// 导航到上一个元素
/// </summary>
public void NavigatePrevious()
{
if (NavigationOrder.Count == 0) return;
_currentIndex--;
if (WrapNavigation)
{
if (_currentIndex < 0)
{
_currentIndex = NavigationOrder.Count - 1;
}
}
else
{
_currentIndex = Mathf.Max(_currentIndex, 0);
}
SetFocus(_currentIndex);
}
/// <summary>
/// 设置焦点到指定索引的元素
/// </summary>
public void SetFocus(int index)
{
if (index < 0 || index >= NavigationOrder.Count) return;
if (_eventSystem == null) return;
var target = NavigationOrder[index];
if (target == null || !target.interactable || !target.gameObject.activeInHierarchy)
{
// 跳过不可用的元素
if (WrapNavigation)
{
NavigateNext();
}
return;
}
_currentIndex = index;
// 设置选中
_eventSystem.SetSelectedGameObject(target.gameObject);
// 如果是InputField激活输入
var inputField = target.GetComponent<TMP_InputField>();
if (inputField != null)
{
inputField.Select();
inputField.ActivateInputField();
}
else
{
var legacyInputField = target.GetComponent<InputField>();
if (legacyInputField != null)
{
legacyInputField.Select();
legacyInputField.ActivateInputField();
}
}
if (ShowDebugInfo)
{
Debug.Log($"TabNavigationSystem: 焦点切换到 {target.name} (索引: {index})");
}
}
/// <summary>
/// 手动添加导航元素
/// </summary>
public void AddNavigationElement(Selectable element)
{
if (element != null && !NavigationOrder.Contains(element))
{
NavigationOrder.Add(element);
}
}
/// <summary>
/// 移除导航元素
/// </summary>
public void RemoveNavigationElement(Selectable element)
{
if (NavigationOrder.Contains(element))
{
int index = NavigationOrder.IndexOf(element);
NavigationOrder.Remove(element);
// 调整当前索引
if (_currentIndex >= index && _currentIndex > 0)
{
_currentIndex--;
}
}
}
/// <summary>
/// 刷新导航列表
/// </summary>
public void RefreshNavigation()
{
if (AutoDetectInputFields)
{
AutoDetectNavigationElements();
}
}
/// <summary>
/// 获取当前焦点元素
/// </summary>
public Selectable GetCurrentElement()
{
if (_currentIndex >= 0 && _currentIndex < NavigationOrder.Count)
{
return NavigationOrder[_currentIndex];
}
return null;
}
/// <summary>
/// 获取当前焦点索引
/// </summary>
public int GetCurrentIndex()
{
return _currentIndex;
}
/// <summary>
/// 跳转到指定元素
/// </summary>
public void FocusElement(Selectable element)
{
int index = NavigationOrder.IndexOf(element);
if (index >= 0)
{
SetFocus(index);
}
}
}
/// <summary>
/// Tab导航辅助组件
/// 可以附加到单独的InputField上提供更精细的控制
/// </summary>
public class TabNavigationHelper : MonoBehaviour
{
[Header("导航设置")]
public Selectable NextElement; // 下一个元素
public Selectable PreviousElement; // 上一个元素
public bool SkipThisElement = false; // 是否跳过此元素
private Selectable _thisSelectable;
void Start()
{
_thisSelectable = GetComponent<Selectable>();
}
void Update()
{
if (SkipThisElement) return;
// 检查是否是当前选中的元素
if (EventSystem.current?.currentSelectedGameObject == gameObject)
{
if (Input.GetKeyDown(KeyCode.Tab))
{
bool reverse = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
if (reverse && PreviousElement != null)
{
FocusElement(PreviousElement);
}
else if (!reverse && NextElement != null)
{
FocusElement(NextElement);
}
}
}
}
private void FocusElement(Selectable element)
{
if (element != null && element.interactable && element.gameObject.activeInHierarchy)
{
EventSystem.current?.SetSelectedGameObject(element.gameObject);
var inputField = element.GetComponent<TMP_InputField>();
if (inputField != null)
{
inputField.Select();
inputField.ActivateInputField();
}
else
{
var legacyInputField = element.GetComponent<InputField>();
if (legacyInputField != null)
{
legacyInputField.Select();
legacyInputField.ActivateInputField();
}
}
}
}
}