unity3d 有没有办法在Unity Isnpector中隐藏EditorGUILayout.ObjectField的“对象选择器”?

q3qa4bjr  于 2023-03-30  发布在  其他
关注(0)|答案(4)|浏览(193)

我只是问是否有任何可能性隐藏“对象选择器”(小旋钮/菜单旁边的一个ObjectField)在自定义检查器.我有一些情况下,更改被禁用(DisableGroup),我想也隐藏旋钮,而内容无论如何不能更改.

另外,为了让用户更容易,我考虑将字段设置得更高(EditorGUIUtility.SingleLineHeight * 2)-〉选择器也会被拉伸,看起来有点糟糕^^
示例:

using UnityEditor;
using UnityEngine;

public class Bla : MonoBehaviour {

    [CustomEditor(typeof(Bla))]
    public class BlaEditor : Editor
    {
        private AudioClip _clip;

        public override void OnInspectorGUI()
        {
            EditorGUI.BeginDisabledGroup(true);
            // do some magic to hide the object picker
            _clip = (AudioClip) EditorGUILayout.ObjectField("some label", _clip, typeof(AudioClip), false);
            EditorGUI.EndDisabledGroup();
        }
    }
}

我想坚持使用ObjectField而不是简单的Label,原因有两个:

  • 即使在禁用的`ObjectField上|“ping”功能仍在工作。(如果你点击它,相应的资产会在层次结构中突出显示。)这显然不是标签的情况。
  • 用户不应该混淆与完全不同的期待控制,但我宁愿只想消除一些不必要的混乱。
3df52oht

3df52oht1#

您可能会找到一种通过使用样式表来隐藏对象选择器的解决方案。
如果你想要的只是 * 显示 * 一些引用,你可以使用一个简单的按钮,基本上像文本字段一样,添加一个图像,然后自己从代码中ping对象。

using UnityEngine;

namespace Test
{
    public class TestBehaviour : MonoBehaviour
    {
        [SerializeField] private bool _audioEnabled;
        [SerializeField] private AudioClip _audioClip;
    }
}

编者:

using System.Reflection;
using UnityEditor;
using UnityEditor.Experimental.UIElements;
using UnityEngine;

namespace Test
{
    [CustomEditor(typeof(TestBehaviour))]
    public class TestBehaviourEditor : Editor
    {
        private SerializedProperty _clipProp;
        private SerializedProperty _audioEnabledProp;
        private ObjectField m_ObjectField;

        private const BindingFlags FIELD_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

        private void OnEnable()
        {
            _clipProp = serializedObject.FindProperty("_audioClip");
            _audioEnabledProp = serializedObject.FindProperty("_audioEnabled");
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUILayout.PropertyField(_audioEnabledProp);

            if(_audioEnabledProp.boolValue)
                EditorGUILayout.PropertyField(_clipProp);
            else
            {
                //TODO: calculate proper layout 

                var type = target.GetType().GetField(_clipProp.propertyPath, FIELD_BINDING_FLAGS).FieldType;
                var clip = _clipProp.objectReferenceValue;

                var guiContent = EditorGUIUtility.ObjectContent(clip, type);

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Fake ObjectField Button");

                var style = new GUIStyle("TextField");
                style.fixedHeight   = 16;
                style.imagePosition = clip ? ImagePosition.ImageLeft : ImagePosition.TextOnly;

                if (GUILayout.Button(guiContent, style ) && clip)
                    EditorGUIUtility.PingObject(clip);

                EditorGUILayout.EndHorizontal();
            }

            serializedObject.ApplyModifiedProperties();
        }
    }
}
gmxoilav

gmxoilav2#

我有另一个解决办法忽略此对象拾取器的拾取结果,虽然拾取器还在,可以显示拾取器窗口,但拾取不工作。
(我仍然不知道如何隐藏这个按钮和pickerwindow,〉〈),这个答案也发布在unity answers上。
下面是代码:

// Register another callback of this object field
     myObjectField.RegisterValueChangedCallback(DefaultObjectFieldCallback);
     
     // In this callback, is a trick
     private void DefaultAssetFieldCallback(ChangeEvent<UnityEngine.Object> evt) {
         // unregister the callback first
         myObjectField.UnregisterValueChangedCallback(DefaultAssetFieldCallback);
     
         // trick: set back to the old value
         m_ConfigAssetField.value = evt.previousValue;
     
         // register the callback again
         myObjectField.RegisterValueChangedCallback(DefaultObjectFieldCallback);
     }
ruoxqz4g

ruoxqz4g3#

我需要做一些类似的事情,并找到了一种方法,通过单步执行UIToolkit调试器中的ObjectField来做到这一点。小对象选择器按钮的类型是隐藏的,所以我们不能真正使用类本身。
这个解决方案使用UIToolkit,所以不幸的是它不能与Unity Editor IMGUI一起工作,但希望它能对某人有所帮助。
简单步骤的解决方案:
1.找出ObjectFieldSelector的uss样式类是什么。
1.递归搜索ObjectField的子级,以查找包含uss样式类的VisualElement。
1.将可见性设置为false。全部完成!

using UnityEditor;
    using UnityEditor.UIElements;
    using UnityEngine.UIElements;

    [CustomPropertyDrawer(typeof(MyClass))]
    public class MyClassDrawer: PropertyDrawer
    {
        public override VisualElement CreatePropertyGUI(SerializedProperty property)
        {
            var field = new ObjectField(property.displayName);
            field.objectType = typeof(MyClass);

            var button = FindChild(field, "unity-object-field__selector");
            button.visible = false;

            return field;
        }

        private VisualElement FindChild(VisualElement parent, string ussClass)
        {
            foreach(var child in parent.Children())
            {
                if (child.ClassListContains(ussClass))
                    return child;

                var subChild = FindChild(child, ussClass);
                if (subChild != null)
                    return subChild;
            }
            return null;
        }
    }
whitzsjs

whitzsjs4#

谢谢你的回答。尝试了更多的工作,使它更像统一内置的一个。

using UnityEngine;
using UnityEditor;

static partial class EditorGUIUtils {

    public static void ObjectDisplayFieldLayout(Object obj, params GUILayoutOption[] options) =>
        ObjectDisplayFieldLayout(obj, (GUIContent)null, options);

    public static void ObjectDisplayFieldLayout(Object obj, string label, params GUILayoutOption[] options) =>
        ObjectDisplayFieldLayout(obj, new GUIContent(label), options);

    public static void ObjectDisplayFieldLayout(Object obj, GUIContent label, params GUILayoutOption[] options) {

        EditorGUILayout.BeginVertical();
        GUILayout.Space(2);
        EditorGUILayout.BeginHorizontal();
        GUILayout.Space(2);

        GUILayout.Space(EditorGUI.indentLevel * 15);

        GUIStyle style = new GUIStyle(GUI.skin.textField);
        style.fixedHeight = EditorGUIUtility.singleLineHeight;
        style.imagePosition = obj != null ? ImagePosition.ImageLeft : ImagePosition.TextOnly;
        style.alignment = TextAnchor.MiddleLeft;

        GUIContent content = EditorGUIUtility.ObjectContent(obj, obj.GetType());

        Rect rect = GUILayoutUtility.GetRect(4, EditorGUIUtility.singleLineHeight, options);
        Rect objRect = rect;
        if (label != null) {
            Rect labelRect = rect;
            labelRect.width = rect.width / 2f - 1f;
            if (labelRect.width >= 1f) {
                EditorGUI.PrefixLabel(labelRect, label);
                objRect = labelRect;
                objRect.x = labelRect.xMax + 2f;
                objRect.width = Mathf.Max(4f, rect.xMax - objRect.x);
            }
        }

        var e = Event.current;
        if (e.type == EventType.MouseDown && e.button == 0 && objRect.Contains(e.mousePosition)) {
            if (obj != null)
                EditorGUIUtility.PingObject(obj);
            e.Use();
        }

        GUI.Button(objRect, content, style);

        GUILayout.Space(1);
        EditorGUILayout.EndHorizontal();
        GUILayout.Space(1);
        EditorGUILayout.EndVertical();
    }
}

像这样使用它

EditorGUILayout.LabelField("Base Texture Reference", EditorStyles.boldLabel);
    if (BaseTextureList.arraySize <= 0) {
        EditorGUILayout.LabelField("not exist", EditorStyles.miniLabel);
    }
    else {
        EditorGUI.indentLevel++;
        for (int i = 0; i < BaseTextureList.arraySize; i++) {
            EditorGUIUtils.ObjectDisplayFieldLayout(BaseTextureList.GetArrayElementAtIndex(i).objectReferenceValue, $"Texture {i}");
        }
        EditorGUI.indentLevel--;
    }

相关问题