HKMBFZ/Assets/Scripts/Szz_Scripts/UI/CustomUI/FocusPage.cs

237 lines
8.3 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;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using System.Reflection;
public class FocusPage : MonoBehaviour
{
[Header("页面焦点元素")]
public List<Selectable> focusElements = new List<Selectable>();
private int currentFocusIndex = -1;
private Coroutine focusCoroutine;
private bool isSwitchingFocus = false;
private CustomTMPInputField currentCustomInputField;
private CustomTMPDropdown currentCustomTMPDropdown;
private bool isDropdownExpanded = false;
public int FocusCount => focusElements.Count;
public int CurrentFocusIndex => currentFocusIndex;
public Selectable CurrentFocus => GetCurrentFocusElement();
public bool HasPreviousFocus => currentFocusIndex > 0;
public bool HasNextFocus => currentFocusIndex < FocusCount - 1;
void OnEnable()
{
FocusManager.Instance?.SetCurrentPage(this);
FindCustomComponents();
ValidateFocusElements();
if (FocusCount > 0) SetFocusImmediate(0);
}
private void FindCustomComponents()
{
focusElements.Clear();
// 获取所有Selectable包括隐藏的
Selectable[] allSelectables = GetComponentsInChildren<Selectable>(true);
foreach (var sel in allSelectables)
{
if (sel != null && sel.interactable)
{
focusElements.Add(sel);
}
}
}
void OnDisable()
{
if (FocusManager.Instance?.GetCurrentPage() == this) ClearFocus();
}
void Update()
{
CheckDropdownState();
}
#region
public void FocusNext()
{
if (isSwitchingFocus) return;
if (isDropdownExpanded) { DropdownSelectNext(); return; }
if (currentFocusIndex + 1 < focusElements.Count) SetFocusDelayed(currentFocusIndex + 1);
}
public void FocusPrevious()
{
if (isSwitchingFocus) return;
if (isDropdownExpanded) { DropdownSelectPrevious(); return; }
if (currentFocusIndex - 1 >= 0) SetFocusDelayed(currentFocusIndex - 1);
}
public void FocusFirst() { if (!isSwitchingFocus && FocusCount > 0) SetFocusDelayed(0); }
public void FocusLast() { if (!isSwitchingFocus && FocusCount > 0) SetFocusDelayed(FocusCount - 1); }
public bool TryMoveToNext()
{
if (isSwitchingFocus || currentFocusIndex + 1 >= FocusCount) return false;
SetFocusDelayed(currentFocusIndex + 1);
return true;
}
public bool TryMoveToPrevious()
{
if (isSwitchingFocus || currentFocusIndex - 1 < 0) return false;
SetFocusDelayed(currentFocusIndex - 1);
return true;
}
#endregion
#region 访
public CustomTMPInputField GetCurrentCustomInputField() => currentCustomInputField;
public void ActivateCurrentInputField() { currentCustomInputField?.Activate(); }
public void DeactivateCurrentInputField() { currentCustomInputField?.Deactivate(); }
public bool HasActiveInputField() => currentCustomInputField != null && currentCustomInputField.HasFocus();
#endregion
#region Dropdown
public void DropdownSelectNext() { if (isDropdownExpanded) currentCustomTMPDropdown?.SelectNext(); }
public void DropdownSelectPrevious() { if (isDropdownExpanded) currentCustomTMPDropdown?.SelectPrevious(); }
public void DropdownSubmit() { if (isDropdownExpanded) currentCustomTMPDropdown?.SubmitSelection(); }
public void DropdownToggle() { if (currentCustomTMPDropdown != null) { currentCustomTMPDropdown.ToggleDropdown(); StartCoroutine(UpdateDropdownNextFrame()); } }
private IEnumerator UpdateDropdownNextFrame() { yield return null; CheckDropdownState(); FocusManager.Instance?.ForceUpdateButtonStates(); }
public bool IsDropdownExpanded() => isDropdownExpanded;
public bool IsOnDropdown() => currentCustomTMPDropdown != null;
public string GetCurrentDropdownValue() => currentCustomTMPDropdown != null && currentCustomTMPDropdown.options.Count > 0 ? currentCustomTMPDropdown.options[currentCustomTMPDropdown.value].text : "";
#endregion
#region
private void SetFocusImmediate(int index)
{
if (index < 0 || index >= focusElements.Count) return;
ClearCurrentFocus();
currentFocusIndex = index;
Selectable target = focusElements[index];
if (EventSystem.current != null)
{
EventSystem.current.SetSelectedGameObject(target.gameObject);
HandleSpecialFocus(target, false);
}
FocusManager.Instance?.ForceUpdateButtonStates();
}
private void SetFocusDelayed(int index, float delay = 0.05f)
{
if (focusCoroutine != null) StopCoroutine(focusCoroutine);
focusCoroutine = StartCoroutine(SetFocusCoroutine(index, delay));
}
private IEnumerator SetFocusCoroutine(int index, float delay)
{
if (isSwitchingFocus) yield break;
isSwitchingFocus = true;
yield return new WaitForSecondsRealtime(delay);
if (index >= 0 && index < focusElements.Count)
{
ClearCurrentFocus();
currentFocusIndex = index;
Selectable target = focusElements[index];
if (EventSystem.current != null && EventSystem.current.currentSelectedGameObject != target.gameObject)
EventSystem.current.SetSelectedGameObject(target.gameObject);
HandleSpecialFocus(target, true);
}
isSwitchingFocus = false;
FocusManager.Instance?.ForceUpdateButtonStates();
}
private void ClearCurrentFocus()
{
currentCustomInputField?.Deactivate();
CloseDropdown();
currentCustomInputField = null;
currentCustomTMPDropdown = null;
isDropdownExpanded = false;
}
private void CloseDropdown()
{
if (currentCustomTMPDropdown != null)
{
currentCustomTMPDropdown.CloseDropdown();
isDropdownExpanded = false;
currentCustomTMPDropdown = null;
}
}
private void HandleSpecialFocus(Selectable element, bool autoExpand)
{
switch (element)
{
case CustomTMPInputField customInputField:
currentCustomInputField = customInputField;
currentCustomTMPDropdown = null;
isDropdownExpanded = false;
customInputField.Activate();
break;
case CustomTMPDropdown customTMPDropdown:
currentCustomTMPDropdown = customTMPDropdown;
currentCustomInputField = null;
if (autoExpand) StartCoroutine(DelayedExpandDropdown());
break;
default:
currentCustomInputField = null;
currentCustomTMPDropdown = null;
isDropdownExpanded = false;
break;
}
FocusManager.Instance?.ForceUpdateButtonStates();
}
private IEnumerator DelayedExpandDropdown()
{
yield return new WaitForSecondsRealtime(0.05f);
currentCustomTMPDropdown?.OpenDropdown();
isDropdownExpanded = true;
}
private void CheckDropdownState()
{
bool wasExpanded = isDropdownExpanded;
if (currentCustomTMPDropdown != null)
{
var dropdownField = typeof(TMP_Dropdown).GetField("m_Dropdown", BindingFlags.NonPublic | BindingFlags.Instance);
if (dropdownField != null)
{
var dropdownGO = dropdownField.GetValue(currentCustomTMPDropdown) as GameObject;
isDropdownExpanded = dropdownGO != null && dropdownGO.activeInHierarchy;
}
else isDropdownExpanded = false;
}
else isDropdownExpanded = false;
if (wasExpanded != isDropdownExpanded)
FocusManager.Instance?.ForceUpdateButtonStates();
}
private Selectable GetCurrentFocusElement() => currentFocusIndex >= 0 && currentFocusIndex < focusElements.Count ? focusElements[currentFocusIndex] : null;
public void ClearFocus()
{
focusElements.Clear();
ClearCurrentFocus();
currentFocusIndex = -1;
if (EventSystem.current != null) EventSystem.current.SetSelectedGameObject(null);
FocusManager.Instance?.ForceUpdateButtonStates();
}
private void ValidateFocusElements() => focusElements.RemoveAll(e => e == null || !e.interactable);
#endregion
}