diff --git a/Editor/OverrideUI/XericToggleEditor.cs b/Editor/OverrideUI/XericToggleEditor.cs index 08e9fd0..35e0a77 100644 --- a/Editor/OverrideUI/XericToggleEditor.cs +++ b/Editor/OverrideUI/XericToggleEditor.cs @@ -18,9 +18,11 @@ namespace XericUIEditor.OverrideUI SerializedProperty m_TextProperty; SerializedProperty m_EnableTextColorTransitionProperty; + SerializedProperty m_isonStatusColor; SerializedProperty m_TextTransitionColorModeProperty; SerializedProperty m_enableTextContextTransitionProperty; SerializedProperty m_textTransitionContextModeProperty; + SerializedProperty m_isonStatusTextContext; protected override void OnEnable() { @@ -34,9 +36,11 @@ namespace XericUIEditor.OverrideUI m_TextProperty = serializedObject.FindProperty("m_text"); m_EnableTextColorTransitionProperty = serializedObject.FindProperty("m_enableTextColorTransition"); + m_isonStatusColor = serializedObject.FindProperty("m_isonStatusColor"); m_TextTransitionColorModeProperty = serializedObject.FindProperty("m_textTransitionColorMode"); m_enableTextContextTransitionProperty = serializedObject.FindProperty("m_enableTextContextTransition"); m_textTransitionContextModeProperty = serializedObject.FindProperty("m_textTransitionContextMode"); + m_isonStatusTextContext = serializedObject.FindProperty("m_isonStatusTextContext"); } public override void OnInspectorGUI() @@ -76,6 +80,7 @@ namespace XericUIEditor.OverrideUI { EditorGUI.indentLevel++; EditorGUILayout.PropertyField(m_TextTransitionColorModeProperty); + EditorGUILayout.PropertyField(m_isonStatusColor); EditorGUI.indentLevel--; } EditorGUILayout.PropertyField(m_enableTextContextTransitionProperty); @@ -83,6 +88,7 @@ namespace XericUIEditor.OverrideUI { EditorGUI.indentLevel++; EditorGUILayout.PropertyField(m_textTransitionContextModeProperty); + EditorGUILayout.PropertyField(m_isonStatusTextContext); EditorGUI.indentLevel--; } diff --git a/Runtime/OverrideLayout/XericScrollRect.cs b/Runtime/OverrideLayout/XericScrollRect.cs index a75c819..4228461 100644 --- a/Runtime/OverrideLayout/XericScrollRect.cs +++ b/Runtime/OverrideLayout/XericScrollRect.cs @@ -56,7 +56,7 @@ namespace XericUI.OverrideLayout /// /// 对象数据 /// - [SerializeField] private readonly List _childrenDatas = ListPool.Get(); + [SerializeField] private readonly List _childrenDatas = new List(); public Vector2 ContextSize { @@ -83,6 +83,7 @@ namespace XericUI.OverrideLayout private Queue _activeQueue = new Queue(); + private bool layoutHasRebuildAtThisFrame; private bool layoutDirty; private bool indexMapDirty; @@ -97,20 +98,21 @@ namespace XericUI.OverrideLayout private bool _uiVisibal; protected GameObject item; - + public RectTransform itemRectTransform => item ? item.RectTransform() : null; + public IUIVesselVisibalControl ItemUIVesselVisibalControlComponent => item ? itemRectTransform.GetComponent() : null; public bool GetUIVisibal => _uiVisibal; public virtual void UnderVisibal() { item = parentScrollRect.childrenPool.Get(); - var rectTransform = item.RectTransform(); parentScrollRect.UpdateChildPivot(layout, item.RectTransform()); - rectTransform.anchoredPosition = layout.position; + itemRectTransform.anchoredPosition = layout.position; } public virtual void OutOfVisibal() { parentScrollRect.childrenPool.DirectlyRelease(item); + item = null; } public void UpdateLayout(GridLayoutCalculator.LayoutItem layoutData) @@ -211,18 +213,22 @@ namespace XericUI.OverrideLayout { // 只有距离大于这个才会触发更新 _lastContextAnchoredPosition = position; - UpdateAAMVSVisibleStatus(position); + UpdateAAMVSVisibleStatus(); } } } protected override void LateUpdate() { + layoutHasRebuildAtThisFrame = false; base.LateUpdate(); // 布局刷新 if (layoutDirty) { layoutDirty = false; + // 常规的刷新依赖视图的更新,如果这一帧只增删了对象,但是视图没有移动,那么这里就会执行更新 + if (layoutHasRebuildAtThisFrame) + UpdateAAMVSVisibleStatus(); RefreshLayout(); } // 全部索引刷新 @@ -239,8 +245,9 @@ namespace XericUI.OverrideLayout /// /// 自动剔除更新标记 /// - protected void UpdateAAMVSVisibleStatus(Vector2 position) + protected void UpdateAAMVSVisibleStatus() { + layoutHasRebuildAtThisFrame = true; // 将视口尺寸转换到content本地空间 // 手动计算视口在content空间的矩形 viewport.GetWorldCorners(viewportVertex); @@ -261,57 +268,68 @@ namespace XericUI.OverrideLayout // horizontal ? horizontalScrollbar?.value ?? 0 : 0, // vertical ? 1 - (verticalScrollbar?.value ?? 1) : 0); - // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop - foreach (RectTransform child in content.GetChildren()) + foreach (var childData in _childrenDatas) { - var visControl = child.GetComponent(); - var isVisControlValid = visControl != null; + var childRectTransform = childData.itemRectTransform; + if (childRectTransform) + { + var visControl = childData.ItemUIVesselVisibalControlComponent; + var isVisControlValid = visControl != null; + + // 直接使用anchoredPosition进行边界检测 + var childPos = childRectTransform.anchoredPosition; + var isVisible = CheckIsVisibal(childPos); + var nowActive = childRectTransform.GetActivity(); - var rectTransform = child.RectTransform(); - // 直接使用anchoredPosition进行边界检测 - var childPos = rectTransform.anchoredPosition; - var isVisible = - childPos.x >= visibleMin.x && - childPos.x <= visibleMax.x && - childPos.y >= visibleMin.y && - childPos.y <= visibleMax.y; + // 以接口为准 + if (isVisControlValid) + nowActive = visControl.GetUIVisibal; - var nowActive = child.GetActivity(); + // 现在的状态与实际一致,跳过 + if (isVisible == nowActive) + continue; - // 以接口为准 - if (isVisControlValid) - nowActive = visControl.GetUIVisibal; - - // 现在的状态与实际一致,跳过 - if (isVisible == nowActive) - continue; - - // 向成员发送状态(如果成员没有实现接口,就直接通过可见性控制) - if (isVisControlValid) - visControl.CallVisibal(isVisible); + // 向成员发送状态(如果成员没有实现接口,就直接通过可见性控制) + if (isVisControlValid) + visControl.CallVisibal(isVisible); + else + childRectTransform.gameObject.SetActive(isVisible); + } else - child.gameObject.SetActive(isVisible); + { + var isVisible = CheckIsVisibal(childData.layout.position); + if (isVisible) + { + childData.UnderVisibal(); + } + } + } + + bool CheckIsVisibal(Vector2 pos) + { + return + pos.x >= visibleMin.x && + pos.x <= visibleMax.x && + pos.y >= visibleMin.y && + pos.y <= visibleMax.y; } } + + #endregion #region 数据管理 - public T GetScrollItemData() - where T : ScrollItemData, new() - { - var result = new T - { - parentScrollRect = this - }; - return result; - } - + /// + /// 添加一个子项(自行重写这个子项类型数据结构,基于其中的生命周期函数完成内容的更新) + /// + /// public void AddChildData(ScrollItemData Data) { layoutDirty = true; Data.index = _childrenDatas.Count; + Data.parentScrollRect = this; _childrenDatas.Add(Data); } diff --git a/Runtime/OverrideUI/XericImage.cs b/Runtime/OverrideUI/XericImage.cs new file mode 100644 index 0000000..51e9a47 --- /dev/null +++ b/Runtime/OverrideUI/XericImage.cs @@ -0,0 +1,59 @@ +using System; +using UnityEngine; +using UnityEngine.Serialization; +using UnityEngine.UI; +using XericUI.Helper; + +namespace XericUI.OverrideUI +{ + /// + /// 图像组件 + /// + /// + /// 这个组件主要为了提供graphic层的事件,用于应对部分无法重写的ui组件事件 + /// + public class XericImage : Image + { + /// + /// 针对toggle的回报(ison) + /// + internal Action OnToggleCrossFadeCall; + public override void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha, bool useRGB) + { + base.CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha, useRGB); + OnToggleCrossFadeCall?.Invoke(targetColor.a > 0); + } + + #region 组件替换 +#if UNITY_EDITOR + [UnityEditor.MenuItem("CONTEXT/Image/Replace To XericImage", true)] + private static bool ValidateReplaceToXeric(UnityEditor.MenuCommand command) + => command.context is Image and not XericImage; + + [UnityEditor.MenuItem("CONTEXT/Image/Replace To XericImage", false, 10)] + private static void ReplaceToXeric(UnityEditor.MenuCommand command) + => command.ReplaceCommandContext( + o => + o.sprite, + (t, d) => + { + t.sprite = d; + }); + + [UnityEditor.MenuItem("CONTEXT/Image/Replace To Image", true)] + private static bool ValidateReplaceToUnity(UnityEditor.MenuCommand command) + => command.context is XericImage; + + [UnityEditor.MenuItem("CONTEXT/Image/Replace To Image", false, 10)] + private static void ReplaceToUnity(UnityEditor.MenuCommand command) + => command.ReplaceCommandContext( + o => + o.sprite, + (t, d) => + { + t.sprite = d; + }); +#endif + #endregion + } +} \ No newline at end of file diff --git a/Runtime/OverrideUI/XericImage.cs.meta b/Runtime/OverrideUI/XericImage.cs.meta new file mode 100644 index 0000000..c7e2db0 --- /dev/null +++ b/Runtime/OverrideUI/XericImage.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 52aeb4e8bd3a4b6c9513b8ad21b41558 +timeCreated: 1776850195 \ No newline at end of file diff --git a/Runtime/OverrideUI/XericToggle.cs b/Runtime/OverrideUI/XericToggle.cs index 9fbcb84..4bff171 100644 --- a/Runtime/OverrideUI/XericToggle.cs +++ b/Runtime/OverrideUI/XericToggle.cs @@ -6,6 +6,7 @@ using UnityEngine; using UnityEngine.Serialization; using UnityEngine.UI; using XericUI.Helper; +using XericUI.OverrideUI; namespace XericUI { @@ -46,6 +47,7 @@ namespace XericUI public bool m_enableTextColorTransition = true; public ColorBlock m_textTransitionColorMode = ColorBlock.defaultColorBlock; + public Color m_isonStatusColor = Color.white; public bool m_enableTextContextTransition = false; public AnimationTriggers m_textTransitionContextMode = new AnimationTriggers() { @@ -55,6 +57,9 @@ namespace XericUI selectedTrigger = "toggle_selected", disabledTrigger = "toggle_disabled", }; + + public string m_isonStatusTextContext = "toggle_ison"; + public bool EnableTextColorTransition { @@ -67,7 +72,39 @@ namespace XericUI get => m_textTransitionColorMode; set => m_textTransitionColorMode = value; } - + + + private XericImage m_ximage; + + protected XericImage ximage + { + get + { + if (m_ximage) + return m_ximage; +#if UNITY_EDITOR + if (!graphic) + return null; +#endif + m_ximage = graphic.GetComponent(); + if (m_ximage) + return m_ximage; + Debug.Log("עÒâÌ滻toggleµÄcheckmarkΪXericImageÒÔ֧³ÖÍêÕûµĹ¦ÄÜ"); + return null; + } + } + + private bool bindXImage; + + protected override void InstantClearState() + { + base.InstantClearState(); + + if (m_enableTextColorTransition) + TextColor = colors.normalColor; + if (m_enableTextContextTransition) + TextContent = m_textTransitionContextMode.normalTrigger; + } protected override void DoStateTransition(SelectionState state, bool instant) { if (!gameObject.activeInHierarchy) @@ -117,8 +154,8 @@ namespace XericUI transitionName = m_textTransitionContextMode.disabledTrigger; break; default: - tintColor = Color.black; - textColor = Color.white; + tintColor = colors.normalColor; + textColor = m_textTransitionColorMode.normalColor; transitionSprite = null; triggerName = string.Empty; transitionName = m_textTransitionContextMode.normalTrigger; @@ -138,13 +175,25 @@ namespace XericUI break; } + if (!bindXImage && ximage != null) + { + bindXImage = true; + ximage.OnToggleCrossFadeCall = b => + { + if (m_enableTextColorTransition) + TextColor = b ? m_textTransitionColorMode.pressedColor : m_textTransitionColorMode.normalColor; + if (m_enableTextContextTransition) + TextContent = b ? m_textTransitionContextMode.pressedTrigger : m_textTransitionContextMode.normalTrigger; + }; + } + + if (m_enableTextColorTransition) - TextColor = isOn ? m_textTransitionColorMode.selectedColor : textColor; + TextColor = isOn ? m_isonStatusColor : textColor; if (m_enableTextContextTransition) TextContent = transitionName; } - - + void StartColorTween(Color targetColor, bool instant) { if (targetGraphic == null) @@ -184,8 +233,9 @@ namespace XericUI => command.context is Toggle and not XericToggle; [UnityEditor.MenuItem("CONTEXT/Toggle/Replace To XericToggle", false, 10)] - private static void ReplaceToXeric(UnityEditor.MenuCommand command) - => command.ReplaceCommandContext( o => (o.graphic, o.group, o.onValueChanged), @@ -195,6 +245,8 @@ namespace XericUI t.group = d.group; t.onValueChanged = d.onValueChanged; }); + Debug.Log("ÇëÊֶ¯Ì滻toggleϵÄCheckmark Image×é¼þΪXericImage£¬·ñÔòToggle¹¤×÷ʱȡÏûѡÔñµÄ״̬»ᱣ³ÖΪison״̬¡£"); + } [UnityEditor.MenuItem("CONTEXT/Toggle/Replace To Toggle", true)] private static bool ValidateReplaceToUnity(UnityEditor.MenuCommand command) @@ -214,5 +266,6 @@ namespace XericUI }); #endif #endregion + } }