Unity:在显式导航中使用自动导航

时间:2018-01-03 10:32:39

标签: unity3d navigation

我想对应用程序中的所有按钮使用显式导航。 但对于一些按钮,我想离开"选择右边"使用自动导航(例如:我知道左,上,下的下一个按钮,但我不知道下一个右键)。

2 个答案:

答案 0 :(得分:3)

如果设置了值,则需要创建可以使用显式导航的自定义Selectable。您可以将此代码用于您的案例,只需在检查器中留下需要使用自动导航的空白字段。

using UnityEngine;
using UnityEngine.UI;

namespace UI.CustomSelectable
{
    public class CustomSelectable : Selectable
    {
        [SerializeField]
        private Selectable upSelectable;

        [SerializeField]
        private Selectable downSelectable;

        [SerializeField]
        private Selectable leftSelectable;

        [SerializeField]
        private Selectable rightSelectable;

        public override Selectable FindSelectableOnUp()
        {
            return upSelectable != null ? upSelectable : base.FindSelectableOnUp();
        }

        public override Selectable FindSelectableOnDown()
        {
            return downSelectable != null ? downSelectable : base.FindSelectableOnDown();
        }

        public override Selectable FindSelectableOnLeft()
        {
            return leftSelectable != null ? leftSelectable : base.FindSelectableOnLeft();
        }

        public override Selectable FindSelectableOnRight()
        {
            return rightSelectable != null ? rightSelectable : base.FindSelectableOnRight();
        }
    }
}

答案 1 :(得分:0)

我基于覆盖 Find...() 方法的想法编写了一个自定义按钮类。也许它对其他人有用。 它为原始答案添加了一些便利功能,例如可能的候选选项列表和检查器按钮以自动填充您的候选选项。

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace YourNameSpace
{
    /// <summary>
    /// Adds lists for each navigation direction.
    /// The first valid selectable in each list will be used or (if none is valid)
    /// then auto navigation will be used as fallback.
    /// </summary>
    public class ButtonSmartNavigation : Button
    {
        public List<Selectable> UpSelectables;
        public List<Selectable> DownSelectables;
        public List<Selectable> LeftSelectables;
        public List<Selectable> RightSelectables;

        public override Selectable FindSelectableOnUp()
        {
            var upSelectable = getFirstSelectable(UpSelectables, this.navigation.selectOnUp);
            return upSelectable != null ? upSelectable : base.FindSelectableOnUp();
        }

        public override Selectable FindSelectableOnDown()
        {
            var downSelectable = getFirstSelectable(DownSelectables, this.navigation.selectOnDown);
            return downSelectable != null ? downSelectable : base.FindSelectableOnDown();
        }

        public override Selectable FindSelectableOnLeft()
        {
            var leftSelectable = getFirstSelectable(LeftSelectables, this.navigation.selectOnLeft);
            return leftSelectable != null ? leftSelectable : base.FindSelectableOnLeft();
        }

        public override Selectable FindSelectableOnRight()
        {
            var rightSelectable = getFirstSelectable(RightSelectables, this.navigation.selectOnRight);
            return rightSelectable != null ? rightSelectable : base.FindSelectableOnRight();
        }

        protected Selectable getFirstSelectable(List<Selectable> list, Selectable defaultExplicit)
        {
            if (list == null)
                return null;

            for (int i = 0; i < list.Count; i++)
            {
                if (list[i] != null && list[i].IsInteractable() && list[i].gameObject.activeInHierarchy)
                {
                    return list[i];
                }
            }

            return defaultExplicit;
        }

        public void AddUpSelectable(Selectable selectable, bool prioritize = false)
        {
            addSelectable(UpSelectables, selectable, prioritize);
        }

        public void AddDownSelectable(Selectable selectable, bool prioritize = false)
        {
            addSelectable(DownSelectables, selectable, prioritize);
        }

        public void AddLeftSelectable(Selectable selectable, bool prioritize = false)
        {
            addSelectable(LeftSelectables, selectable, prioritize);
        }

        public void AddRightSelectable(Selectable selectable, bool prioritize = false)
        {
            addSelectable(RightSelectables, selectable, prioritize);
        }

        protected void addSelectable(List<Selectable> list, Selectable selectable, bool prioritize)
        {
            if (list == null)
            {
                list = new List<Selectable>();
            }

            if (prioritize)
            {
                list.Insert(0, selectable);
            }
            else
            {
                list.Add(selectable);
            }
        }

        public void Clear()
        {
            UpSelectables.Clear();
            DownSelectables.Clear();
            LeftSelectables.Clear();
            RightSelectables.Clear();
        }
    }

#if UNITY_EDITOR
    [CustomEditor(typeof(ButtonSmartNavigation), true)]
    [CanEditMultipleObjects]
    public class ButtonSmartNavigationEditor : UnityEditor.UI.ButtonEditor
    {
        protected SerializedProperty upSelectables;
        protected SerializedProperty downSelectables;
        protected SerializedProperty leftSelectables;
        protected SerializedProperty rightSelectables;

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            var target = this.target as ButtonSmartNavigation;

            if (upSelectables == null) upSelectables = serializedObject.FindProperty("UpSelectables");
            if (downSelectables == null) downSelectables = serializedObject.FindProperty("DownSelectables");
            if (leftSelectables == null) leftSelectables = serializedObject.FindProperty("LeftSelectables");
            if (rightSelectables == null) rightSelectables = serializedObject.FindProperty("RightSelectables");

            EditorGUILayout.LabelField("Smart Navigation", EditorStyles.boldLabel);

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Up"))
            {
                target.UpSelectables.Clear();
                target.AddUpSelectable(target.FindSelectableOnUp());
                EditorUtility.SetDirty(target);
            }
            if (GUILayout.Button("Down"))
            {
                target.DownSelectables.Clear();
                target.AddDownSelectable(target.FindSelectableOnDown());
                EditorUtility.SetDirty(target);
            }
            if (GUILayout.Button("Left"))
            {
                target.LeftSelectables.Clear();
                target.AddLeftSelectable(target.FindSelectableOnLeft());
                EditorUtility.SetDirty(target);
            }
            if (GUILayout.Button("Right"))
            {
                target.RightSelectables.Clear();
                target.AddRightSelectable(target.FindSelectableOnRight());
                EditorUtility.SetDirty(target);
            }
            if (GUILayout.Button("Clear"))
            {
                target.Clear();
                EditorUtility.SetDirty(target);
            }
            GUILayout.EndHorizontal();

            serializedObject.Update();
            EditorGUILayout.PropertyField(upSelectables, new GUIContent("Up Selectables"));
            EditorGUILayout.PropertyField(downSelectables, new GUIContent("Down Selectables"));
            EditorGUILayout.PropertyField(leftSelectables, new GUIContent("Left Selectables"));
            EditorGUILayout.PropertyField(rightSelectables, new GUIContent("Right Selectables"));
            serializedObject.ApplyModifiedProperties();
        }
    }
#endif
}