// ---------------- FocusManager ---------------- using UnityEngine; using UnityEngine.UI; using TMPro; using System.Collections; public class FocusManager : MonoBehaviour { public static FocusManager Instance { get; private set; } [Header("导航按钮")] public Button nextFocusButton; public Button previousFocusButton; public Button firstFocusButton; public Button lastFocusButton; [Header("下拉菜单控制按钮")] public Button dropdownToggleButton; public Button dropdownNextButton; public Button dropdownPreviousButton; public Button dropdownSubmitButton; [Header("状态显示")] public TextMeshProUGUI dropdownStatusText; public TextMeshProUGUI pageStatusText; public TextMeshProUGUI inputStatusText; [Header("调试")] public TextMeshProUGUI debugText; public FocusPage currentPage; private bool isProcessingInput = false; void Awake() { if (Instance == null) { Instance = this;} //else { Destroy(gameObject); return; } SetupButtonListeners(); } void Update() { HandleKeyboardNavigation(); UpdateStatusDisplay(); UpdateDebugInfo(); } public void ForceUpdateButtonStates() => UpdateButtonStates(); public void SetCurrentPage(FocusPage page) { if (page == null) return; currentPage?.ClearFocus(); currentPage = page; ForceUpdateButtonStates(); UpdateStatusDisplay(); } public FocusPage GetCurrentPage() => currentPage; #region 焦点导航 public void FocusNext() { if (currentPage == null || isProcessingInput || currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.FocusNext())); } public void FocusPrevious() { if (currentPage == null || isProcessingInput || currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.FocusPrevious())); } public void FocusFirst() { if (currentPage == null || isProcessingInput || currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.FocusFirst())); } public void FocusLast() { if (currentPage == null || isProcessingInput|| currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.FocusLast())); } public void DropdownSelectNext() { if (currentPage == null || isProcessingInput || currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.DropdownSelectNext())); } public void DropdownSelectPrevious() { if (currentPage == null || isProcessingInput || currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.DropdownSelectPrevious())); } public void DropdownSubmit() { if (currentPage == null || isProcessingInput || currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.DropdownSubmit())); } public void DropdownToggle() { if (currentPage == null || isProcessingInput || currentPage.focusDisabled) return; StartCoroutine(ProcessInputCoroutine(() => currentPage.DropdownToggle())); } private IEnumerator ProcessInputCoroutine(System.Action action) { if (isProcessingInput) yield break; isProcessingInput = true; action?.Invoke(); // 不要等到 EndOfFrame yield return null; isProcessingInput = false; UpdateButtonStates(); } #endregion #region 按钮状态 private void SetupButtonListeners() { if (nextFocusButton != null) nextFocusButton.onClick.AddListener(FocusNext); if (previousFocusButton != null) previousFocusButton.onClick.AddListener(FocusPrevious); if (firstFocusButton != null) firstFocusButton.onClick.AddListener(FocusFirst); if (lastFocusButton != null) lastFocusButton.onClick.AddListener(FocusLast); if (dropdownToggleButton != null) dropdownToggleButton.onClick.AddListener(DropdownToggle); if (dropdownNextButton != null) dropdownNextButton.onClick.AddListener(DropdownSelectNext); if (dropdownPreviousButton != null) dropdownPreviousButton.onClick.AddListener(DropdownSelectPrevious); if (dropdownSubmitButton != null) dropdownSubmitButton.onClick.AddListener(DropdownSubmit); } // 这里省略其他未改动部分,主要修改按钮状态逻辑 private void UpdateButtonStates() { if (currentPage == null) { SetAllButtonsInteractable(false); return; } bool isDropdownExpanded = currentPage.IsDropdownExpanded(); bool isOnDropdown = currentPage.IsOnDropdown(); bool hasInputFocus = currentPage.HasActiveInputField(); if (previousFocusButton != null) previousFocusButton.interactable = currentPage.HasPreviousFocus && !isDropdownExpanded && !hasInputFocus && !isProcessingInput; if (nextFocusButton != null) nextFocusButton.interactable = currentPage.HasNextFocus && !isDropdownExpanded && !hasInputFocus && !isProcessingInput; bool hasElements = currentPage.FocusCount > 0 && !isDropdownExpanded && !hasInputFocus && !isProcessingInput; if (firstFocusButton != null) firstFocusButton.interactable = hasElements; if (lastFocusButton != null) lastFocusButton.interactable = hasElements; // Submit可用条件 if (dropdownToggleButton != null) dropdownToggleButton.interactable = isOnDropdown && !hasInputFocus && !isProcessingInput; if (dropdownNextButton != null) dropdownNextButton.interactable = isDropdownExpanded && !hasInputFocus && !isProcessingInput; if (dropdownPreviousButton != null) dropdownPreviousButton.interactable = isDropdownExpanded && !hasInputFocus && !isProcessingInput; if (dropdownSubmitButton != null) dropdownSubmitButton.interactable = (isDropdownExpanded || isOnDropdown) && !hasInputFocus && !isProcessingInput; } private void SetAllButtonsInteractable(bool interactable) { if (previousFocusButton != null) previousFocusButton.interactable = interactable; if (nextFocusButton != null) nextFocusButton.interactable = interactable; if (firstFocusButton != null) firstFocusButton.interactable = interactable; if (lastFocusButton != null) lastFocusButton.interactable = interactable; if (dropdownToggleButton != null) dropdownToggleButton.interactable = interactable; if (dropdownNextButton != null) dropdownNextButton.interactable = interactable; if (dropdownPreviousButton != null) dropdownPreviousButton.interactable = interactable; if (dropdownSubmitButton != null) dropdownSubmitButton.interactable = interactable; } #endregion #region 状态显示 private void UpdateStatusDisplay() { if (currentPage == null) { if (dropdownStatusText != null) dropdownStatusText.text = "无活动页面"; if (pageStatusText != null) pageStatusText.text = ""; if (inputStatusText != null) inputStatusText.text = ""; return; } if (pageStatusText != null) pageStatusText.text = $"焦点: {currentPage.CurrentFocusIndex + 1}/{currentPage.FocusCount}"; if (inputStatusText != null) inputStatusText.text = currentPage.HasActiveInputField() ? "输入模式" : ""; if (dropdownStatusText != null) { if (currentPage.IsDropdownExpanded()) { dropdownStatusText.text = $"选择中: {currentPage.GetCurrentDropdownValue()}"; } else if (currentPage.IsOnDropdown()) { dropdownStatusText.text = "按[提交]开始选择"; } else dropdownStatusText.text = ""; } } private void UpdateDebugInfo() { if (debugText != null && currentPage != null) { debugText.text = $"处理中: {isProcessingInput}\n" + $"输入焦点: {currentPage.HasActiveInputField()}\n" + $"下拉展开: {currentPage.IsDropdownExpanded()}"; } } #endregion #region 键盘导航 private void HandleKeyboardNavigation() { if (currentPage == null) return; bool hasInputFocus = currentPage.HasActiveInputField(); if (hasInputFocus) { if (Input.GetKeyDown(KeyCode.Escape)) StartCoroutine(ProcessInputCoroutine(() => currentPage.DeactivateCurrentInputField())); return; } // Dropdown键盘操作,直接调用 if (currentPage.IsOnDropdown()) { if (Input.GetKeyDown(KeyCode.UpArrow)) currentPage.DropdownSelectPrevious(); if (Input.GetKeyDown(KeyCode.DownArrow)) currentPage.DropdownSelectNext(); //if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter)) // currentPage.DropdownSubmit(); // 内部判断是打开还是提交 //if (Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.Escape)) // currentPage.DropdownToggle(); } else { //// 普通焦点切换用协程限制重复输入 //if (Input.GetKeyDown(KeyCode.Tab)) //{ // if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) // SafeFocusPrevious(); // else // SafeFocusNext(); //} if (Input.GetKeyDown(KeyCode.Home)) FocusFirst(); if (Input.GetKeyDown(KeyCode.End)) FocusLast(); } } #endregion }