有没有办法在 Unity Inspector 中隐藏 EditorGUILayout.ObjectField 的 "Object picker"?

Is there any way to hide the "Object picker" of an EditorGUILayout.ObjectField in Unity Isnpector?

我只是问是否有可能在自定义检查器中隐藏 "Object Picker"(ObjectField 旁边的小 knob/menu)。我有一些情况下更改被禁用 (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 而不是简单的标签,原因有二:

您可能会找到使用样式表隐藏对象选取器的解决方案。

如果您只想显示一些参考,您可以使用一个基本样式为文本字段的简单按钮,添加图像并自己从代码中 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();
        }
    }
}

我有另一个解决方案:忽略这个对象选择器的选择结果,虽然选择器还在,可以显示选择器window,选择up 不行。

(我还是不知道怎么隐藏这个按钮和选择器window,><),这个答案也发布在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);
     }

我需要做一些类似的事情,并找到了一种通过单步执行 UIToolkit 调试器中的 ObjectField 来完成此操作的方法。小对象选择器按钮的类型是隐藏的,所以我们不能真正使用 class 本身。

此解决方案使用的是 UIToolkit,因此很遗憾,它不能与 Unity Editor IMGUI 一起使用,但希望它会对某人有所帮助。

简单步骤的解决方案:

  1. 找出 ObjectFieldSelector 的 uss 样式 class 是什么。
  2. 递归搜索 ObjectField 的子项以查找包含 uss 样式的 VisualElement class。
  3. 将可见性设置为假。 全部完成!
    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;
        }
    }