rmv
This commit is contained in:
parent
b50ab115a9
commit
7b4feec0f0
@ -76,8 +76,7 @@ namespace UnityEngine.UI
|
||||
{
|
||||
Press();
|
||||
PlayAudio(clickAudioClip);
|
||||
// if we get set disabled during the press
|
||||
// don't run the coroutine.
|
||||
|
||||
if (!IsActive() || !IsInteractable())
|
||||
return;
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ namespace UnityEngine.UI
|
||||
[SerializeField]
|
||||
private List<UXToggle> m_Toggles = new List<UXToggle>();
|
||||
|
||||
// 新增:默认选中的 Toggle(可在 Inspector 设置)
|
||||
[SerializeField]
|
||||
private UXToggle m_DefaultToggle;
|
||||
|
||||
@ -76,7 +75,6 @@ namespace UnityEngine.UI
|
||||
if (m_Toggles.Contains(toggle))
|
||||
m_Toggles.Remove(toggle);
|
||||
|
||||
// 如果被移除的正好是默认选项,则清空默认项
|
||||
if (m_DefaultToggle == toggle)
|
||||
{
|
||||
m_DefaultToggle = null;
|
||||
@ -91,32 +89,27 @@ namespace UnityEngine.UI
|
||||
if (!m_Toggles.Contains(toggle))
|
||||
m_Toggles.Add(toggle);
|
||||
|
||||
// 当组内已有其他开启项,并且不允许 all-off 时,
|
||||
// 如果新加入的 toggle 本身为 on,则需要把它关闭以维持单选。
|
||||
|
||||
if (!allowSwitchOff)
|
||||
{
|
||||
// 如果已经有一个 active 的 toggle(且不是刚加入的这个),并且刚加入的 toggle isOn 为 true,则关闭刚加入的 toggle
|
||||
|
||||
var firstActive = GetFirstActiveToggle();
|
||||
if (firstActive != null && firstActive != toggle && toggle.isOn)
|
||||
{
|
||||
// 我们使用不触发回调的方式避免编辑时产生不必要的事件调用
|
||||
toggle.SetIsOnWithoutNotify(false);
|
||||
}
|
||||
else if (firstActive == null)
|
||||
{
|
||||
// 没有任何 active 且不允许 all-off:如果 group 指定了 defaultToggle,优先选中它(但仅当 default 在本组内且可交互)
|
||||
if (m_DefaultToggle != null && m_Toggles.Contains(m_DefaultToggle))
|
||||
{
|
||||
var dt = m_DefaultToggle;
|
||||
if (dt != null && dt != toggle)
|
||||
{
|
||||
// 确保默认项被选中(editor/runtime 都适用)
|
||||
dt.isOn = true;
|
||||
NotifyToggleOn(dt);
|
||||
}
|
||||
else if (dt == toggle)
|
||||
{
|
||||
// 新加入项就是默认项,确保它为 on
|
||||
toggle.isOn = true;
|
||||
NotifyToggleOn(toggle);
|
||||
}
|
||||
@ -125,22 +118,19 @@ namespace UnityEngine.UI
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:判断组里是否包含某 toggle(用于运行时/编辑器避免重复注册)
|
||||
|
||||
public bool ContainsToggle(UXToggle toggle)
|
||||
{
|
||||
return m_Toggles != null && m_Toggles.Contains(toggle);
|
||||
}
|
||||
|
||||
// Ensure list consistency: clean nulls, and make sure every toggle in this list actually references this group.
|
||||
public void EnsureValidState()
|
||||
{
|
||||
if (m_Toggles == null)
|
||||
m_Toggles = new List<UXToggle>();
|
||||
|
||||
// Remove null references first
|
||||
m_Toggles.RemoveAll(x => x == null);
|
||||
|
||||
// 如果不允许 all-off,优先尝试选中 defaultToggle,否则选中第一个。
|
||||
if (!allowSwitchOff && !AnyTogglesOn() && m_Toggles.Count != 0)
|
||||
{
|
||||
UXToggle toSelect = null;
|
||||
@ -164,7 +154,6 @@ namespace UnityEngine.UI
|
||||
|
||||
if (activeToggles.Count() > 1)
|
||||
{
|
||||
// 如果 defaultToggle 是开启的,优先保留它
|
||||
UXToggle firstActive = GetFirstActiveToggle();
|
||||
|
||||
foreach (UXToggle toggle in activeToggles)
|
||||
@ -178,8 +167,6 @@ namespace UnityEngine.UI
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronize each toggle's group reference to this group if necessary,
|
||||
// but avoid causing re-ordering in cases where it's already consistent.
|
||||
for (int i = 0; i < m_Toggles.Count; i++)
|
||||
{
|
||||
var t = m_Toggles[i];
|
||||
@ -188,7 +175,6 @@ namespace UnityEngine.UI
|
||||
|
||||
if (t.group != this)
|
||||
{
|
||||
// 使用 setter 会触发必要的注册/注销逻辑
|
||||
t.group = this;
|
||||
}
|
||||
}
|
||||
@ -206,7 +192,6 @@ namespace UnityEngine.UI
|
||||
|
||||
public UXToggle GetFirstActiveToggle()
|
||||
{
|
||||
// 优先返回 defaultToggle(如果它处于 on 且在组内)
|
||||
if (m_DefaultToggle != null && m_Toggles.Contains(m_DefaultToggle) && m_DefaultToggle.isOn)
|
||||
return m_DefaultToggle;
|
||||
|
||||
|
||||
@ -101,10 +101,9 @@ namespace UnityEngine.UI
|
||||
base.OnDidApplyAnimationProperties();
|
||||
}
|
||||
|
||||
// Centralized group setter logic.
|
||||
|
||||
private void SetToggleGroup(UXGroup newGroup, bool setMemberValue)
|
||||
{
|
||||
// 如果组没有改变,仍然需要确保组里包含此 toggle(修复编辑器中批量拖拽只注册最后一项的问题)
|
||||
if (m_Group == newGroup)
|
||||
{
|
||||
if (setMemberValue)
|
||||
@ -115,21 +114,18 @@ namespace UnityEngine.UI
|
||||
newGroup.RegisterToggle(this);
|
||||
}
|
||||
|
||||
// 尝试同步组状态,确保编辑器批量赋值时能稳定显示
|
||||
if (newGroup != null)
|
||||
newGroup.EnsureValidState();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 从旧组注销(如果存在)
|
||||
if (m_Group != null)
|
||||
m_Group.UnregisterToggle(this);
|
||||
|
||||
if (setMemberValue)
|
||||
m_Group = newGroup;
|
||||
|
||||
// 注册到新组(不再强依赖 IsActive(),以保证编辑器批量赋值时也能正确注册)
|
||||
if (newGroup != null)
|
||||
{
|
||||
if (!newGroup.ContainsToggle(this))
|
||||
@ -137,11 +133,9 @@ namespace UnityEngine.UI
|
||||
newGroup.RegisterToggle(this);
|
||||
}
|
||||
|
||||
// 如果正在 on,通知组(维持单选逻辑)
|
||||
if (isOn)
|
||||
newGroup.NotifyToggleOn(this);
|
||||
|
||||
// 同步组的内部状态,确保 Inspector 列表正确显示
|
||||
newGroup.EnsureValidState();
|
||||
}
|
||||
}
|
||||
@ -157,19 +151,14 @@ namespace UnityEngine.UI
|
||||
Set(value, false);
|
||||
}
|
||||
|
||||
// 在 UXToggle 类内(建议放在类底部较靠近 Set 和 PlayEffect 的位置)加入:
|
||||
|
||||
// 覆盖 DoStateTransition,保证 isOn 时视觉上总是 Selected(除非 Disabled)
|
||||
protected override void DoStateTransition(Selectable.SelectionState state, bool instant)
|
||||
{
|
||||
// 如果被禁用,照常显示 Disabled
|
||||
if (state == Selectable.SelectionState.Disabled)
|
||||
{
|
||||
base.DoStateTransition(state, instant);
|
||||
return;
|
||||
}
|
||||
|
||||
// 当 isOn 为 true 时,总是以 Selected 的样式渲染(但不改变 EventSystem 的真实 selection)
|
||||
if (m_IsOn)
|
||||
state = Selectable.SelectionState.Selected;
|
||||
|
||||
@ -199,11 +188,8 @@ namespace UnityEngine.UI
|
||||
onValueChanged.Invoke(m_IsOn);
|
||||
}
|
||||
|
||||
// 触发选择态视觉刷新(当 isOn 为 true 显示 Selected,false 时回到 normal/hover/... 的计算结果)
|
||||
// instant 参数:如果 ToggleTransition 是 None 我们使用 instant,为保持和原来 PlayEffect 一致。
|
||||
bool instant = (toggleTransition == Toggle.ToggleTransition.None);
|
||||
// 传入的 state:当 isOn 为 true,DoStateTransition 会将其替换为 Selected;
|
||||
// 当 isOn 为 false,使用 currentSelectionState 以让正常的鼠标/键盘状态生效。
|
||||
|
||||
var stateToApply = m_IsOn ? Selectable.SelectionState.Selected : currentSelectionState;
|
||||
DoStateTransition(stateToApply, instant);
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ namespace UnityEngine.UI
|
||||
}
|
||||
}
|
||||
|
||||
// 改成 Component[](或 MonoBehaviour[]),Unity 可以序列化 Component 引用
|
||||
[SerializeField] private Component[] hotButtons;
|
||||
|
||||
internal void BindHotKeys()
|
||||
|
||||
@ -16,7 +16,6 @@ namespace UnityEngine.UI
|
||||
Performed = 1
|
||||
}
|
||||
|
||||
// 优化1: 使用struct减少GC
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
internal struct HotkeyRegistration
|
||||
{
|
||||
@ -31,7 +30,6 @@ namespace UnityEngine.UI
|
||||
}
|
||||
}
|
||||
|
||||
// 优化2: 使用struct存储handler信息
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HandlerInfo
|
||||
{
|
||||
@ -47,28 +45,23 @@ namespace UnityEngine.UI
|
||||
|
||||
internal static class UXHotkeyRegisterManager
|
||||
{
|
||||
// 优化3: 使用数组池替代List,避免频繁扩容
|
||||
private const int INITIAL_CAPACITY = 32;
|
||||
private const int MAX_REGISTRATIONS_PER_ACTION = 16;
|
||||
|
||||
// 优化4: 使用固定大小的数组池
|
||||
private static HotkeyRegistration[][] _registrationPool;
|
||||
private static int[] _registrationCounts;
|
||||
private static string[] _actionIds;
|
||||
private static int _actionCount;
|
||||
private static int _actionCapacity;
|
||||
|
||||
// 优化5: 使用数组替代Dictionary(更快的查找)
|
||||
private static HandlerInfo[] _handlers;
|
||||
private static InputActionReference[] _actionRefs;
|
||||
|
||||
// 优化6: Button到ActionId的映射(使用数组索引)
|
||||
private static IHotkeyTrigger[] _buttons;
|
||||
private static int[] _buttonToActionIndex;
|
||||
private static int _buttonCount;
|
||||
private static int _buttonCapacity;
|
||||
|
||||
// 优化7: 缓存委托,避免每次创建
|
||||
private static Action<InputAction.CallbackContext>[] _cachedHandlers;
|
||||
private static int _cachedHandlerCount;
|
||||
|
||||
@ -128,7 +121,6 @@ namespace UnityEngine.UI
|
||||
string actionId = action.action.id.ToString();
|
||||
int actionIndex = FindOrCreateActionIndex(actionId);
|
||||
|
||||
// 添加注册信息
|
||||
ref int count = ref _registrationCounts[actionIndex];
|
||||
if (count >= MAX_REGISTRATIONS_PER_ACTION)
|
||||
{
|
||||
@ -139,11 +131,9 @@ namespace UnityEngine.UI
|
||||
_registrationPool[actionIndex][count] = new HotkeyRegistration(button, pressType);
|
||||
count++;
|
||||
|
||||
// 记录button映射
|
||||
int buttonIndex = FindOrCreateButtonIndex(button);
|
||||
_buttonToActionIndex[buttonIndex] = actionIndex;
|
||||
|
||||
// 优化8: 只在第一次注册时创建handler
|
||||
if (count == 1)
|
||||
{
|
||||
Action<InputAction.CallbackContext> handler = GetOrCreateHandler(actionIndex);
|
||||
@ -178,7 +168,6 @@ namespace UnityEngine.UI
|
||||
if (actionIndex < 0)
|
||||
return;
|
||||
|
||||
// 从注册列表中移除
|
||||
ref int count = ref _registrationCounts[actionIndex];
|
||||
HotkeyRegistration[] registrations = _registrationPool[actionIndex];
|
||||
|
||||
@ -188,12 +177,10 @@ namespace UnityEngine.UI
|
||||
{
|
||||
EHotkeyPressType pressType = registrations[i].pressType;
|
||||
|
||||
// 优化9: Swap-remove,避免数组移动
|
||||
registrations[i] = registrations[count - 1];
|
||||
registrations[count - 1] = default;
|
||||
count--;
|
||||
|
||||
// 如果是最后一个注册,清理handler
|
||||
if (count == 0)
|
||||
{
|
||||
ref HandlerInfo handlerInfo = ref _handlers[actionIndex];
|
||||
@ -223,12 +210,10 @@ namespace UnityEngine.UI
|
||||
}
|
||||
}
|
||||
|
||||
// 清理button映射
|
||||
_buttons[buttonIndex] = null;
|
||||
_buttonToActionIndex[buttonIndex] = -1;
|
||||
}
|
||||
|
||||
// 优化10: 使用缓存的委托,避免闭包分配
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Action<InputAction.CallbackContext> GetOrCreateHandler(int actionIndex)
|
||||
{
|
||||
@ -242,7 +227,6 @@ namespace UnityEngine.UI
|
||||
Array.Resize(ref _cachedHandlers, actionIndex + 1);
|
||||
}
|
||||
|
||||
// 优化11: 使用静态方法 + 参数传递,避免闭包
|
||||
int capturedIndex = actionIndex;
|
||||
_cachedHandlers[actionIndex] = ctx => OnHotkeyTriggered(capturedIndex);
|
||||
return _cachedHandlers[actionIndex];
|
||||
@ -254,24 +238,20 @@ namespace UnityEngine.UI
|
||||
int count = _registrationCounts[actionIndex];
|
||||
if (count > 0)
|
||||
{
|
||||
// 触发最后一个注册的button(栈顶)
|
||||
ref HotkeyRegistration registration = ref _registrationPool[actionIndex][count - 1];
|
||||
registration.button?.HotkeyActionTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
// 优化12: 线性查找(小数据集比Dictionary更快)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int FindOrCreateActionIndex(string actionId)
|
||||
{
|
||||
// 查找现有
|
||||
for (int i = 0; i < _actionCount; i++)
|
||||
{
|
||||
if (_actionIds[i] == actionId)
|
||||
return i;
|
||||
}
|
||||
|
||||
// 创建新的
|
||||
if (_actionCount >= _actionCapacity)
|
||||
{
|
||||
ExpandActionCapacity();
|
||||
@ -285,14 +265,12 @@ namespace UnityEngine.UI
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int FindOrCreateButtonIndex(IHotkeyTrigger button)
|
||||
{
|
||||
// 查找现有
|
||||
for (int i = 0; i < _buttonCount; i++)
|
||||
{
|
||||
if (ReferenceEquals(_buttons[i], button))
|
||||
return i;
|
||||
}
|
||||
|
||||
// 查找空槽
|
||||
for (int i = 0; i < _buttonCapacity; i++)
|
||||
{
|
||||
if (_buttons[i] == null)
|
||||
@ -304,7 +282,6 @@ namespace UnityEngine.UI
|
||||
}
|
||||
}
|
||||
|
||||
// 扩容
|
||||
if (_buttonCount >= _buttonCapacity)
|
||||
{
|
||||
ExpandButtonCapacity();
|
||||
@ -358,7 +335,6 @@ namespace UnityEngine.UI
|
||||
_buttonCapacity = newCapacity;
|
||||
}
|
||||
|
||||
// 优化13: 批量操作API
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RegisterHotkeyBatch(Span<IHotkeyTrigger> buttons, InputActionReference action, EHotkeyPressType pressType)
|
||||
{
|
||||
@ -377,7 +353,6 @@ namespace UnityEngine.UI
|
||||
}
|
||||
}
|
||||
|
||||
// 调试信息
|
||||
#if UNITY_EDITOR
|
||||
public static string GetDebugInfo()
|
||||
{
|
||||
@ -411,7 +386,6 @@ public static class UXHotkeyHotkeyExtension
|
||||
}
|
||||
}
|
||||
|
||||
// 优化14: 批量绑定
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void BindHotKeyBatch(this IHotkeyTrigger[] buttons)
|
||||
{
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user