init push 0.2.4
This commit is contained in:
64
Runtime/UI/AutoCanvasScale.cs
Normal file
64
Runtime/UI/AutoCanvasScale.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using XericLibrary.Runtime.CustomEditor;
|
||||
|
||||
namespace Deconstruction.Runtime.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><>ȡ<EFBFBD><C8A1>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class AutoCanvasScale : MonoBehaviour
|
||||
{
|
||||
#region <EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
public CanvasScaler canvasScaler;
|
||||
|
||||
[Rename("<22><><EFBFBD>Ƴߴ<C6B3>")]
|
||||
public Vector2 StandardSize = new Vector2(1920,1080);
|
||||
|
||||
public Vector2 ScaleMinMax = new Vector2(0.5f, 2);
|
||||
|
||||
#endregion
|
||||
|
||||
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
FindCanvasScaler();
|
||||
GetScreenScale();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
FindCanvasScaler();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
canvasScaler.scaleFactor = GetScreenScale();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
private void FindCanvasScaler()
|
||||
{
|
||||
if (canvasScaler == null)
|
||||
canvasScaler = transform.GetComponent<CanvasScaler>();
|
||||
}
|
||||
|
||||
private float GetScreenScale()
|
||||
{
|
||||
Vector2 screenSize = new Vector2(Screen.width, Screen.height);
|
||||
// Debug.Log(canvasScaler.referenceResolution);
|
||||
var sf = screenSize / StandardSize;
|
||||
return Mathf.Clamp(Mathf.Min(sf.x, sf.y), ScaleMinMax.x, ScaleMinMax.y);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
429
Runtime/UI/CircleSlider.cs
Normal file
429
Runtime/UI/CircleSlider.cs
Normal file
@@ -0,0 +1,429 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Deconstruction.Runtime.UI
|
||||
{
|
||||
public class CircleSlider : Selectable, IDragHandler, IEndDragHandler, IBeginDragHandler
|
||||
{
|
||||
[SerializeField] private RectTransform m_HandleRect;
|
||||
|
||||
public RectTransform handleRect
|
||||
{
|
||||
get { return m_HandleRect; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_HandleRect, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private RectTransform m_FillRect;
|
||||
|
||||
public RectTransform fillrect
|
||||
{
|
||||
get { return m_FillRect; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_FillRect, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_MinValue = 0;
|
||||
|
||||
public float minValue
|
||||
{
|
||||
get => m_MinValue;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_MinValue, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_MaxValue = 1;
|
||||
|
||||
public float maxValue
|
||||
{
|
||||
get { return m_MaxValue; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_MaxValue, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_Value;
|
||||
|
||||
public float value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (wholeNumbers)
|
||||
return Mathf.Round(m_Value);
|
||||
return m_Value;
|
||||
}
|
||||
set { Set(value); }
|
||||
}
|
||||
|
||||
[SerializeField] private Image.Origin360 m_FillOrigin;
|
||||
|
||||
public Image.Origin360 fillOrigin
|
||||
{
|
||||
get { return m_FillOrigin; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_FillOrigin, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_Radius;
|
||||
|
||||
public float radius
|
||||
{
|
||||
get { return m_Radius; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_Radius, value))
|
||||
{
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_ClockWise;
|
||||
|
||||
public bool clockWise
|
||||
{
|
||||
get { return m_ClockWise; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_ClockWise, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_WholeNumbers = false;
|
||||
|
||||
public bool wholeNumbers
|
||||
{
|
||||
get { return m_WholeNumbers; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_WholeNumbers, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float normalizedValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mathf.Approximately(m_MinValue, m_MaxValue))
|
||||
return 0;
|
||||
return Mathf.InverseLerp(m_MinValue, m_MaxValue, value);
|
||||
}
|
||||
|
||||
set { this.value = Mathf.Lerp(m_MinValue, m_MaxValue, value); }
|
||||
}
|
||||
|
||||
private Action<float> m_OnValueChanged;
|
||||
private Action m_OnDragEnd;
|
||||
private Action m_OnTweenComplete;
|
||||
private Image m_FillImage;
|
||||
private bool m_DelayedUpdateVisuals = false;
|
||||
private bool m_dragHandler;
|
||||
private Camera m_eventCamera;
|
||||
private Coroutine m_TweenCor;
|
||||
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
Set(m_Value);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
if (IsActive())
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
Set(m_Value, false);
|
||||
m_DelayedUpdateVisuals = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (m_DelayedUpdateVisuals)
|
||||
{
|
||||
m_DelayedUpdateVisuals = false;
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateCachedReferences()
|
||||
{
|
||||
if (m_FillRect != null)
|
||||
{
|
||||
m_FillImage = m_FillRect.GetComponent<Image>();
|
||||
m_FillImage.fillMethod = Image.FillMethod.Radial360;
|
||||
m_FillImage.fillOrigin = (int)m_FillOrigin;
|
||||
m_FillImage.fillClockwise = m_ClockWise;
|
||||
}
|
||||
}
|
||||
|
||||
private bool MayDrag(PointerEventData eventData)
|
||||
{
|
||||
return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!MayDrag(eventData))
|
||||
return;
|
||||
if (m_dragHandler)
|
||||
{
|
||||
Vector2 localCursor;
|
||||
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(m_FillRect, eventData.position,
|
||||
eventData.pressEventCamera, out localCursor))
|
||||
return;
|
||||
float angle = CalAngle(localCursor);
|
||||
normalizedValue = (angle / 360);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
m_dragHandler = false;
|
||||
if (m_OnDragEnd != null)
|
||||
{
|
||||
m_OnDragEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (m_HandleRect != null)
|
||||
{
|
||||
if (RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position,
|
||||
eventData.enterEventCamera))
|
||||
{
|
||||
m_dragHandler = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dragHandler = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private float CalAngle(Vector2 pos)
|
||||
{
|
||||
float angle = 0;
|
||||
float rad = Mathf.Atan2(pos.y, pos.x) * Mathf.Rad2Deg;
|
||||
switch (m_FillOrigin)
|
||||
{
|
||||
case Image.Origin360.Top:
|
||||
angle = m_ClockWise ? 90 - rad : rad + 270;
|
||||
break;
|
||||
case Image.Origin360.Left:
|
||||
angle = m_ClockWise ? 180 - rad : rad + 180;
|
||||
break;
|
||||
case Image.Origin360.Right:
|
||||
angle = m_ClockWise ? -rad : rad;
|
||||
break;
|
||||
case Image.Origin360.Bottom:
|
||||
angle = m_ClockWise ? 270 - rad : rad + 90;
|
||||
break;
|
||||
}
|
||||
|
||||
if (angle > 360)
|
||||
{
|
||||
angle -= 360;
|
||||
}
|
||||
|
||||
if (angle < 0)
|
||||
{
|
||||
angle += 360;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
private void UpdateVisuals()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
UpdateCachedReferences();
|
||||
#endif
|
||||
if (m_FillImage != null)
|
||||
{
|
||||
m_FillImage.fillAmount = normalizedValue;
|
||||
}
|
||||
|
||||
if (m_HandleRect != null)
|
||||
{
|
||||
m_HandleRect.transform.localPosition = CalPos(normalizedValue * 360);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 CalPos(float angle)
|
||||
{
|
||||
Vector2 pos = Vector2.zero;
|
||||
switch (m_FillOrigin)
|
||||
{
|
||||
case Image.Origin360.Left:
|
||||
angle = m_ClockWise ? 180 - angle : angle + 180;
|
||||
break;
|
||||
case Image.Origin360.Top:
|
||||
angle = m_ClockWise ? 90 - angle : angle + 90;
|
||||
break;
|
||||
case Image.Origin360.Right:
|
||||
angle = m_ClockWise ? -angle : angle;
|
||||
break;
|
||||
case Image.Origin360.Bottom:
|
||||
angle = m_ClockWise ? 270 - angle : angle - 90;
|
||||
break;
|
||||
}
|
||||
|
||||
angle = Mathf.Deg2Rad * angle;
|
||||
pos.y = Mathf.Sin(angle) * m_Radius;
|
||||
pos.x = Mathf.Cos(angle) * m_Radius;
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
private void Set(float input, bool sendCallback = true)
|
||||
{
|
||||
float newValue = ClampValue(input);
|
||||
if (m_Value == newValue)
|
||||
return;
|
||||
|
||||
m_Value = newValue;
|
||||
UpdateVisuals();
|
||||
if (sendCallback)
|
||||
{
|
||||
if (m_OnValueChanged != null)
|
||||
{
|
||||
m_OnValueChanged.Invoke(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float ClampValue(float input)
|
||||
{
|
||||
float newValue = Mathf.Clamp(input, m_MinValue, m_MaxValue);
|
||||
if (wholeNumbers)
|
||||
newValue = Mathf.Round(newValue);
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public void OnValueChange(Action<float> call)
|
||||
{
|
||||
m_OnValueChanged = call;
|
||||
}
|
||||
|
||||
public void OnDragEnd(Action call)
|
||||
{
|
||||
m_OnDragEnd = call;
|
||||
}
|
||||
|
||||
public void TweenValue(float val, float time, Action call = null)
|
||||
{
|
||||
m_TweenCor = StartCoroutine(_tweenValue(val, time));
|
||||
m_OnTweenComplete = call;
|
||||
}
|
||||
|
||||
public void StopTween()
|
||||
{
|
||||
if (m_TweenCor != null)
|
||||
{
|
||||
StopCoroutine(m_TweenCor);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator _tweenValue(float val, float time)
|
||||
{
|
||||
float t = 0;
|
||||
float oldValue = value;
|
||||
float interval = val - oldValue;
|
||||
|
||||
while (t < time)
|
||||
{
|
||||
t += Time.deltaTime;
|
||||
value = oldValue + (t / time) * interval;
|
||||
yield return 0;
|
||||
}
|
||||
|
||||
if (m_OnTweenComplete != null)
|
||||
{
|
||||
m_OnTweenComplete();
|
||||
}
|
||||
|
||||
value = val;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class SetPropertyUtility
|
||||
{
|
||||
public static bool SetColor(ref Color currentValue, Color newValue)
|
||||
{
|
||||
if (currentValue.r == newValue.r && currentValue.g == newValue.g && currentValue.b == newValue.b &&
|
||||
currentValue.a == newValue.a)
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(currentValue, newValue))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
|
||||
{
|
||||
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
494
Runtime/UI/MacroUI.cs
Normal file
494
Runtime/UI/MacroUI.cs
Normal file
@@ -0,0 +1,494 @@
|
||||
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;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
using Sirenix.OdinInspector;
|
||||
#if UNITY_EDITOR
|
||||
using Sirenix.Utilities.Editor;
|
||||
#endif
|
||||
|
||||
namespace XericLibrary.Runtime.MacroLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// UI相关的扩展
|
||||
/// </summary>
|
||||
public static class MacroUI
|
||||
{
|
||||
#region toggle 扩展
|
||||
|
||||
private static FieldInfo togglesFieldInfo = typeof(ToggleGroup).GetField("m_Toggles", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
public static List<Toggle> 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<Toggle>;
|
||||
if (toggles == null)
|
||||
{
|
||||
throw new InvalidCastException("The 'm_Toggles' field is not of type List<Toggle>.");
|
||||
}
|
||||
|
||||
return toggles;
|
||||
// return (List<Toggle>)togglesFieldInfo.GetValue(toggleGroup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前单选项组中激活的索引
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
/// <returns></returns>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前单选项组的数量
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetToggleCount(this ToggleGroup toggleGroup)
|
||||
{
|
||||
return toggleGroup.GetToggles().Count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 在单选项组上注册一个事件,当组中的任意成员变成激活状态时调用(其他的不会发生调用)。
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
/// <param name="onToggleChange"></param>
|
||||
public static void OnToggleGroupChangeEvent(this ToggleGroup toggleGroup, Action<Toggle> onToggleChange)
|
||||
{
|
||||
foreach (var toggle in toggleGroup.GetToggles())
|
||||
{
|
||||
toggle.onValueChanged.AddListener(a =>
|
||||
{
|
||||
if (!a) return;
|
||||
onToggleChange?.Invoke(toggle);
|
||||
});
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 清空单选项组中的所有事件(与注册所有事件对应,但那个事件没法单独注销)
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
public static void RemoveToggleGroupChangeEvent(this ToggleGroup toggleGroup)
|
||||
{
|
||||
foreach (var toggle in toggleGroup.GetToggles())
|
||||
{
|
||||
toggle.onValueChanged.RemoveAllListeners();
|
||||
}
|
||||
}
|
||||
|
||||
#region toggle 索引
|
||||
|
||||
/// <summary>
|
||||
/// toggle映射集
|
||||
/// <code>
|
||||
/// toggle映射集必须使用unity序列化管理,否则和直接使用toggleGroup没区别,目的是解决toggleGroup在打包后大纲视图的索引可能发生错位的问题。
|
||||
/// </code>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ToggleMapping : IEnumerable<Toggle>
|
||||
{
|
||||
#region 事件委托
|
||||
|
||||
/// <summary>
|
||||
/// 在单选项目切换时产生回调,返回选中的单选项目在组中的引用
|
||||
/// </summary>
|
||||
public Action<Toggle> OnAnyToggleSwitchOn;
|
||||
|
||||
/// <summary>
|
||||
/// 在单选项目切换时产生回调,返回选中的单选项目在组中的索引
|
||||
/// </summary>
|
||||
public Action<int> OnAnyToggleIndexSwitchOn;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字段属性
|
||||
|
||||
[LabelText("单选组")] public ToggleGroup ToggleGroup;
|
||||
|
||||
[SerializeField, LabelText("编辑单选项目顺序")]
|
||||
[ListDrawerSettings(OnTitleBarGUI = "GetAndSortToggle")]
|
||||
private List<Toggle> toggleList = new List<Toggle>();
|
||||
|
||||
// 当前选中的项目
|
||||
private int nowSelectToggleIndex = 0;
|
||||
private Toggle nowSelectToggle = null;
|
||||
|
||||
|
||||
public Transform TogglesContext => ToggleGroup.transform;
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的toggle索引
|
||||
/// </summary>
|
||||
public int NowSelectToggleIndex => nowSelectToggleIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的toggle
|
||||
/// </summary>
|
||||
public Toggle NowSelectToggle => nowSelectToggle;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取并给列表排序(顺序不一定与拼音有关)
|
||||
/// </summary>
|
||||
public void GetAndSortToggle()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// 自动获取并排序
|
||||
if (SirenixEditorGUI.ToolbarButton(EditorIcons.Refresh))
|
||||
{
|
||||
var newToggleList = MacroSort.FullCharacterOrderSort(ToggleGroup.GetToggles(), a => a.name).ToList();
|
||||
if (newToggleList.Count <= 0 || newToggleList == null)
|
||||
Debug.LogError("如果无法更新获取自动排序toggle,可能是因为toggleGroup被隐藏了,手动将其激活后再获取即可。");
|
||||
else
|
||||
toggleList = newToggleList;
|
||||
}
|
||||
// 反转顺序
|
||||
if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleDown))
|
||||
{
|
||||
toggleList.Reverse();
|
||||
}
|
||||
#else
|
||||
var newToggleList = MacroSort.FullCharacterOrderSort(ToggleGroup.GetToggles(), a => a.name).ToList();
|
||||
if (newToggleList.Count <= 0 || newToggleList == null)
|
||||
Debug.LogError("如果无法更新获取自动排序toggle,可能是因为toggleGroup被隐藏了,手动将其激活后再获取即可。");
|
||||
else
|
||||
toggleList = newToggleList;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 接口
|
||||
|
||||
/// <summary>
|
||||
/// 获取索引下的单选项组件
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public Toggle this[int index] => toggleList[index];
|
||||
|
||||
public int Count => toggleList.Count;
|
||||
|
||||
public IEnumerator<Toggle> GetEnumerator()
|
||||
{
|
||||
return toggleList.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// <code>
|
||||
/// 自动将所有的按键绑定回调事件;如果作为刷新函数调用,请确保已经完全组索引。
|
||||
/// 或者可以直接清空旧项目(CleanToggle),然后逐个添加(AddToggle)
|
||||
/// </code>
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个toggle
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns>返回toggle的索引</returns>
|
||||
public int AddToggle(Toggle t)
|
||||
{
|
||||
ToggleAddEvent(t);
|
||||
|
||||
var resultIndex = toggleList.Count;
|
||||
toggleList.Add(t);
|
||||
return resultIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除一个toggle,这不会影响其他toggle的索引,但此处移除的位置会为空。
|
||||
/// <code>
|
||||
/// 注 :这不会销毁toggle。
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns>是否成功移除toggle</returns>
|
||||
public bool RemoveToggle(Toggle t)
|
||||
{
|
||||
var index = toggleList.IndexOf(t);
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
t.onValueChanged.RemoveAllListeners();
|
||||
toggleList[index] = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除toggle
|
||||
/// </summary>
|
||||
/// <param name="allowDestroy">是否同时销毁所有toggle</param>
|
||||
public void CleanToggle(bool allowDestroy)
|
||||
{
|
||||
foreach (var t in toggleList)
|
||||
{
|
||||
t.onValueChanged.RemoveAllListeners();
|
||||
if (allowDestroy)
|
||||
Object.Destroy(t);
|
||||
}
|
||||
toggleList.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// toggle注册的事件,只有当按下时才需要调用此事件。
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
private void ToggleAddEvent(Toggle t)
|
||||
{
|
||||
t.onValueChanged.AddListener(a =>
|
||||
{
|
||||
if (a) ToggleRegister(t);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// toggle注册的事件,只有当按下时才需要调用此事件。
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
private void ToggleRegister(Toggle t)
|
||||
{
|
||||
nowSelectToggle = t;
|
||||
nowSelectToggleIndex = GetIndex(t);
|
||||
OnAnyToggleSwitchOn?.Invoke(t);
|
||||
OnAnyToggleIndexSwitchOn?.Invoke(nowSelectToggleIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取toggle代表的索引
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <returns>如果这个toggle不存在于当前的单选项组中,返回-1</returns>
|
||||
public int GetIndex(Toggle target)
|
||||
{
|
||||
return toggleList.IndexOf(target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取toggle代表的索引, 如果toggle不存在于这个映射集中,将返回否
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGetIndex(Toggle target, out int index)
|
||||
{
|
||||
index = toggleList.IndexOf(target);
|
||||
return index >= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
public void SetToggleOn(Toggle target)
|
||||
{
|
||||
target.isOn = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void SetToggleOn(int index)
|
||||
{
|
||||
if (0 < index && index < toggleList.Count)
|
||||
{
|
||||
SetToggleOn(toggleList[index]);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
public void SetToggleOnWithoutNotify(Toggle target)
|
||||
{
|
||||
target.SetIsOnWithoutNotify(true);
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void SetToggleOnWithoutNotify(int index)
|
||||
{
|
||||
if (0 < index && index < toggleList.Count)
|
||||
{
|
||||
SetToggleOnWithoutNotify(toggleList[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 清除映射结构(不会清除toggle实例)
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
ToggleGroup.RemoveToggleGroupChangeEvent();
|
||||
toggleList.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除映射结构,并销毁所有toggle组件
|
||||
/// </summary>
|
||||
public void RemoveAllToggle()
|
||||
{
|
||||
for (int i = toggleList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Object.Destroy(toggleList[i]);
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region 按钮扩展
|
||||
|
||||
/// <summary>
|
||||
/// 所有按钮注册一个事件
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="targetEvent"></param>
|
||||
public static void RegisterOnClickEvent(this IEnumerable<Button> buttons, UnityAction targetEvent)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.onClick.AddListener(targetEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有按钮注销一个事件
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="targetEvent"></param>
|
||||
public static void LogoutOnClickEvent(this IEnumerable<Button> buttons, UnityAction targetEvent)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.onClick.RemoveListener(targetEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置所有按钮的可交互性
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="interactable"></param>
|
||||
public static void SetButtonInteractable(this IEnumerable<Button> buttons, bool interactable)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.interactable = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 文本组件扩展
|
||||
|
||||
public static void SetText(this IEnumerable<TextMeshProUGUI> texts, string text)
|
||||
{
|
||||
foreach (var t in texts)
|
||||
{
|
||||
t.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI变换获取扩展
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个组件的矩形变换组件
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static RectTransform RectTransform<T>(this T target)
|
||||
where T : Component
|
||||
=> target.transform as RectTransform;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
95
Runtime/UI/WeaklyUIBehaviour.cs
Normal file
95
Runtime/UI/WeaklyUIBehaviour.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
|
||||
namespace Deconstruction.Runtime.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// <20>ṩui<75><69><EFBFBD><EFBFBD><EFBFBD>ϵĽű<C4BD>
|
||||
/// </summary>
|
||||
public class WeaklyUIBehaviour : MonoBehaviour
|
||||
{
|
||||
#region <EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
/// <summary>
|
||||
/// <20>˴<EFBFBD><CBB4>ľ<EFBFBD><C4BE>α任<CEB1><E4BBBB><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public RectTransform rectTransform { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>Canvas
|
||||
/// </summary>
|
||||
public Canvas CanvasRoot { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>Canvas<61>µ<EFBFBD>CanvasScaler
|
||||
/// </summary>
|
||||
public CanvasScaler CanvasRootScaler { get; private set; }
|
||||
|
||||
private bool isFirstOnEnable = false;
|
||||
private bool isFirstOnEnableStart = false;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// <20>ڼ<EFBFBD><DABC>ؽű<D8BD>ʵ<EFBFBD><CAB5>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
protected virtual void Awake()
|
||||
{
|
||||
rectTransform = transform as RectTransform;
|
||||
CanvasRoot = transform.GetParents()
|
||||
.Select(t => t.GetComponent<Canvas>())
|
||||
.FirstOrDefault(a => a != null);
|
||||
if (CanvasRoot != null)
|
||||
CanvasRootScaler = CanvasRoot.GetComponent<CanvasScaler>();
|
||||
else
|
||||
{
|
||||
Debug.LogError($"<22><>Ա{name}<7D><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>ui<75><69>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD>û<EFBFBD>з<EFBFBD><D0B7><EFBFBD><EFBFBD><EFBFBD>canvas<61>ϣ<EFBFBD><CFA3><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD><DEB7>ҵ<EFBFBD>ui<75><69><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
}
|
||||
|
||||
isFirstOnEnable = true;
|
||||
isFirstOnEnableStart = true;
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (isFirstOnEnable)
|
||||
{
|
||||
isFirstOnEnable = false;
|
||||
OnFirstEnable();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20>״<EFBFBD><D7B4><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD>ڽ<EFBFBD><DABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڼ<EFBFBD><DABC>״γ<D7B4>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
protected virtual void OnFirstEnable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
if (isFirstOnEnableStart)
|
||||
{
|
||||
isFirstOnEnableStart = false;
|
||||
OnFirstEnableStart();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20>״<EFBFBD><D7B4><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ʼʱ<CABC><CAB1><EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD>ڽ<EFBFBD><DABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڼ<EFBFBD><DABC>״γ<D7B4>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
protected virtual void OnFirstEnableStart()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user