using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using XericLibrary.Runtime.CustomEditor;
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;
#endif
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.Utilities.Editor;
#endif
using Object = UnityEngine.Object;
namespace XericLibrary.Runtime.MacroLibrary
{
///
/// UI相关的扩展
///
public static class MacroUI
{
#region toggle 扩展
private static FieldInfo togglesFieldInfo = typeof(ToggleGroup).GetField("m_Toggles",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
public static List GetToggles(this ToggleGroup toggleGroup)
{
if (toggleGroup == null)
{
throw new ArgumentNullException(nameof(toggleGroup));
}
if (togglesFieldInfo == null)
{
throw new InvalidOperationException("Unable to access the 'm_Toggles' field.");
}
var toggles = togglesFieldInfo.GetValue(toggleGroup) as List;
if (toggles == null)
{
throw new InvalidCastException("The 'm_Toggles' field is not of type List.");
}
return toggles;
// return (List)togglesFieldInfo.GetValue(toggleGroup);
}
///
/// 获取当前单选项组中激活的索引
///
///
///
[Obsolete("索引依赖单选项自身在大纲中的顺序,在运行时顺序可能与编辑时不一致,请使用ToggleMapping")]
public static int GetActiveToggleIndex(this ToggleGroup toggleGroup)
{
var index = -1;
foreach (var toggle in toggleGroup.GetToggles())
{
index++;
if (toggle.isOn)
return index;
}
return -1;
}
///
/// 获取当前单选项组的数量
///
///
///
public static int GetToggleCount(this ToggleGroup toggleGroup)
{
return toggleGroup.GetToggles().Count;
}
///
/// 在单选项组上注册一个事件,当组中的任意成员变成激活状态时调用(其他的不会发生调用)。
///
///
///
public static void OnToggleGroupChangeEvent(this ToggleGroup toggleGroup, Action onToggleChange)
{
foreach (var toggle in toggleGroup.GetToggles())
{
toggle.onValueChanged.AddListener(a =>
{
if (!a) return;
onToggleChange?.Invoke(toggle);
});
}
}
///
/// 清空单选项组中的所有事件(与注册所有事件对应,但那个事件没法单独注销)
///
///
public static void RemoveToggleGroupChangeEvent(this ToggleGroup toggleGroup)
{
foreach (var toggle in toggleGroup.GetToggles())
{
toggle.onValueChanged.RemoveAllListeners();
}
}
#region toggle 索引
///
/// toggle映射集
///
/// toggle映射集必须使用unity序列化管理,否则和直接使用toggleGroup没区别,目的是解决toggleGroup在打包后大纲视图的索引可能发生错位的问题。
///
///
[Serializable]
public class ToggleMapping : IEnumerable
{
#region 事件委托
///
/// 在单选项目切换时产生回调,返回选中的单选项目在组中的引用
///
public Action OnAnyToggleSwitchOn;
///
/// 在单选项目切换时产生回调,返回选中的单选项目在组中的索引
///
public Action OnAnyToggleIndexSwitchOn;
#endregion
#region 字段属性
#if ODIN_INSPECTOR
[LabelText("单选组")]
#endif
public ToggleGroup ToggleGroup;
#if ODIN_INSPECTOR
[SerializeField, LabelText("编辑单选项目顺序")] [ListDrawerSettings(OnTitleBarGUI = "GetAndSortToggle")]
#endif
private List toggleList = new List();
// 当前选中的项目
private int nowSelectToggleIndex = 0;
private Toggle nowSelectToggle = null;
public Transform TogglesContext => ToggleGroup.transform;
///
/// 当前选中的toggle索引
///
public int NowSelectToggleIndex => nowSelectToggleIndex;
///
/// 当前选中的toggle
///
public Toggle NowSelectToggle => nowSelectToggle;
///
/// 获取并给列表排序(顺序不一定与拼音有关)
///
public void GetAndSortToggle()
{
#if UNITY_EDITOR && ODIN_INSPECTOR
// 自动获取并排序
if (SirenixEditorGUI.ToolbarButton(EditorIcons.Refresh))
{
GetSortToggle();
}
// 反转顺序
if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleDown))
{
toggleList.Reverse();
}
#else
GetSortToggle();
#endif
void GetSortToggle()
{
var newToggleList = MacroSort.FullCharacterOrderSort(ToggleGroup.GetToggles(), a => a.name)
.ToList();
if (newToggleList.Count <= 0 || newToggleList == null)
Debug.LogError("如果无法更新获取自动排序toggle,可能是因为toggleGroup被隐藏了,手动将其激活后再获取即可。");
else
toggleList = newToggleList;
}
}
#endregion
#region 接口
///
/// 获取索引下的单选项组件
///
///
public Toggle this[int index] => toggleList[index];
public int Count => toggleList.Count;
public IEnumerator GetEnumerator()
{
return toggleList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region 方法
///
/// 初始化
///
/// 自动将所有的按键绑定回调事件;如果作为刷新函数调用,请确保已经完全组索引。
/// 或者可以直接清空旧项目(CleanToggle),然后逐个添加(AddToggle)
///
///
public void Initialize()
{
// 未指定组时,说明压根没用这部分功能,用不着初始化。
if (ToggleGroup == null)
return;
// 防呆警告
if (toggleList.Count <= 0)
{
var toggles = ToggleGroup.GetToggles();
if (toggles.Count != toggleList.Count)
{
toggleList = toggles;
Debug.LogWarning($"在初始化单选项组时,{ToggleGroup.name}并未预先指定索引顺序,将默认使用大纲顺序。");
}
}
// 事件初始化
for (int i = 0; i < toggleList.Count; i++)
{
var toggle = toggleList[i];
ToggleAddEvent(toggle);
if (toggle.isOn)
{
nowSelectToggleIndex = i;
nowSelectToggle = toggle;
}
}
if (nowSelectToggle == null)
SetToggleOn(0);
}
///
/// 添加一个toggle
///
///
/// 返回toggle的索引
public int AddToggle(Toggle t)
{
ToggleAddEvent(t);
var resultIndex = toggleList.Count;
toggleList.Add(t);
return resultIndex;
}
///
/// 移除一个toggle,这不会影响其他toggle的索引,但此处移除的位置会为空。
///
/// 注 :这不会销毁toggle。
///
///
///
/// 是否成功移除toggle
public bool RemoveToggle(Toggle t)
{
var index = toggleList.IndexOf(t);
if (index < 0)
return false;
t.onValueChanged.RemoveAllListeners();
toggleList[index] = null;
return true;
}
///
/// 清除toggle
///
/// 是否同时销毁所有toggle
public void CleanToggle(bool allowDestroy)
{
foreach (var t in toggleList)
{
t.onValueChanged.RemoveAllListeners();
if (allowDestroy)
Object.Destroy(t);
}
toggleList.Clear();
}
///
/// toggle注册的事件,只有当按下时才需要调用此事件。
///
///
private void ToggleAddEvent(Toggle t)
{
t.onValueChanged.AddListener(a =>
{
if (a) ToggleRegister(t);
});
}
///
/// toggle注册的事件,只有当按下时才需要调用此事件。
///
///
private void ToggleRegister(Toggle t)
{
nowSelectToggle = t;
nowSelectToggleIndex = GetIndex(t);
OnAnyToggleSwitchOn?.Invoke(t);
OnAnyToggleIndexSwitchOn?.Invoke(nowSelectToggleIndex);
}
///
/// 获取toggle代表的索引
///
///
/// 如果这个toggle不存在于当前的单选项组中,返回-1
public int GetIndex(Toggle target)
{
return toggleList.IndexOf(target);
}
///
/// 获取toggle代表的索引, 如果toggle不存在于这个映射集中,将返回否
///
///
///
///
public bool TryGetIndex(Toggle target, out int index)
{
index = toggleList.IndexOf(target);
return index >= 0;
}
///
/// 设置单选项激活
///
///
public void SetToggleOn(Toggle target)
{
target.isOn = true;
}
///
/// 设置单选项激活
///
///
public void SetToggleOn(int index)
{
if (0 < index && index < toggleList.Count)
{
SetToggleOn(toggleList[index]);
}
}
///
/// 设置单选项激活
///
///
public void SetToggleOnWithoutNotify(Toggle target)
{
target.SetIsOnWithoutNotify(true);
}
///
/// 设置单选项激活
///
///
public void SetToggleOnWithoutNotify(int index)
{
if (0 < index && index < toggleList.Count)
{
SetToggleOnWithoutNotify(toggleList[index]);
}
}
///
/// 清除映射结构(不会清除toggle实例)
///
public void Clear()
{
ToggleGroup.RemoveToggleGroupChangeEvent();
toggleList.Clear();
}
///
/// 清除映射结构,并销毁所有toggle组件
///
public void RemoveAllToggle()
{
for (int i = toggleList.Count - 1; i >= 0; i--)
{
Object.Destroy(toggleList[i]);
}
Clear();
}
#endregion
}
#endregion
#endregion
#region 按钮扩展
///
/// 所有按钮注册一个事件
///
///
///
public static void RegisterOnClickEvent(this IEnumerable