如何使 Vector3 字段的行为类似于 CustomEditor 中 Transform 中的字段
How to make Vector3 fields behave like the ones from Transform in a CustomEditor
在下面的 gif 中,您可以看到 Vector3
字段在 Transform
和我的 MonoBehaviour
的检查器中的行为方式的区别。
这个Transform
连一个CustomEditor
我也是用EditorGUILayout.Vector3Field()
写的。
[CustomEditor(typeof(Transform), true)]
[CanEditMultipleObjects]
public class AdvancedTransformEditor : Editor
{
//Unity's built-in editor
private Editor _defaultEditor;
private Transform _transform;
private void OnEnable()
{
//When this inspector is created, also create the built-in inspector
_defaultEditor = CreateEditor(targets, Type.GetType("UnityEditor.TransformInspector, UnityEditor"));
_transform = target as Transform;
}
private void OnDisable()
{
//When OnDisable is called, the default editor we created should be destroyed to avoid memory leakage.
//Also, make sure to call any required methods like OnDisable
var disableMethod = _defaultEditor.GetType().GetMethod("OnDisable", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (disableMethod != null) disableMethod.Invoke(_defaultEditor, null);
DestroyImmediate(_defaultEditor);
}
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Local Space", EditorStyles.boldLabel);
_defaultEditor.OnInspectorGUI();
serializedObject.Update();
//Show World Space Transform
EditorGUILayout.Space();
EditorGUILayout.LabelField("World Space", EditorStyles.boldLabel);
_transform.position = EditorGUILayout.Vector3Field("Position", _transform.position);
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.Vector3Field("Rotation", _transform.eulerAngles);
EditorGUILayout.Vector3Field("Scale", _transform.lossyScale);
EditorGUI.EndDisabledGroup();
serializedObject.ApplyModifiedProperties();
}
}
它只有在有 _defaultEditor.OnInspectorGUI();
时才有效,所以 Unity 的原始编辑器中的 Transform
组件必须做一些不同的事情。
当我尝试在任何其他 CustomEditor
中对 MonoBehaviour
执行相同操作时
// without a CustomEditor
public class Example : MonoBehaviour
{
public Vector3 example;
}
和
// Width the custom editor
public class ExampleMinWidth : MonoBehaviour
{
public Vector3 example;
}
[CustomEditor(typeof(ExampleMinWidth))]
public class ExampleMinWidthEditor : Editor
{
private SerializedProperty example;
private void OnEnable()
{
example = serializedObject.FindProperty("exmaple");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value);
// I tried both also simply using a PropertyField
//EditorGUILayout.PropertyField(example);
serializedObject.ApplyModifiedProperties();
}
}
或跳过 AdvancedTransformEditor
中的 _defaultEditor.OnInspectorGUI();
行 Vector3
字段会折叠到特定的 Inspector 宽度。
如何让我的字段获得与 Transform
组件相同的行为 - 不折叠但保持在同一行?
更新
我用 GUILayout.MinWidth()
试过了,但这并没有改变任何东西。
按照提示我也试过了
example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value, GUILayout.ExpandHeight(false));
(也适用于 PropertyField()
)但这并没有改变任何东西。
而且只是为了尝试我也用 ExpandWidth(false)
...结果不是很令人满意:D
我什至尝试了 GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight)
但这使得字段仍然折叠但是 "bload"/overdraw 到下面的字段中。
Unity3d 有其 source code available on GitHub, where you can see the Transform 组件实现。
TransformInspector.cs:
/ Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using UnityEngine;
namespace UnityEditor
{
[CustomEditor(typeof(Transform))]
[CanEditMultipleObjects]
internal class TransformInspector : Editor
{
SerializedProperty m_Position;
SerializedProperty m_Scale;
TransformRotationGUI m_RotationGUI;
class Contents
{
public GUIContent positionContent = EditorGUIUtility.TrTextContent("Position", "The local position of this GameObject relative to the parent.");
public GUIContent scaleContent = EditorGUIUtility.TrTextContent("Scale", "The local scaling of this GameObject relative to the parent.");
public string floatingPointWarning = LocalizationDatabase.GetLocalizedString("Due to floating-point precision limitations, it is recommended to bring the world coordinates of the GameObject within a smaller range.");
}
static Contents s_Contents;
public void OnEnable()
{
m_Position = serializedObject.FindProperty("m_LocalPosition");
m_Scale = serializedObject.FindProperty("m_LocalScale");
if (m_RotationGUI == null)
m_RotationGUI = new TransformRotationGUI();
m_RotationGUI.OnEnable(serializedObject.FindProperty("m_LocalRotation"), EditorGUIUtility.TrTextContent("Rotation", "The local rotation of this GameObject relative to the parent."));
}
public override void OnInspectorGUI()
{
if (s_Contents == null)
s_Contents = new Contents();
if (!EditorGUIUtility.wideMode)
{
EditorGUIUtility.wideMode = true;
EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
}
serializedObject.Update();
Inspector3D();
// Warning if global position is too large for floating point errors.
// SanitizeBounds function doesn't even support values beyond 100000
Transform t = target as Transform;
Vector3 pos = t.position;
if (Mathf.Abs(pos.x) > 100000 || Mathf.Abs(pos.y) > 100000 || Mathf.Abs(pos.z) > 100000)
EditorGUILayout.HelpBox(s_Contents.floatingPointWarning, MessageType.Warning);
serializedObject.ApplyModifiedProperties();
}
private void Inspector3D()
{
EditorGUILayout.PropertyField(m_Position, s_Contents.positionContent);
m_RotationGUI.RotationField();
EditorGUILayout.PropertyField(m_Scale, s_Contents.scaleContent);
}
}
}
中找到了相关行
if (!EditorGUIUtility.wideMode)
{
EditorGUIUtility.wideMode = true;
EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
}
EditorGUIUtility.wideMode 做两件事:Returns 编辑器当前是否是 widemode 和 set 此组件/下一行的编辑器是否应该像在 widemode 下一样工作。所以他们只是强制他们的字段在宽模式下仅 "be"。
之后需要使用 "fixed" EditorGUIUtility.labelWidth 即减少 3 Vectror3
字段在宽模式下的宽度(Unity 使用 212)
在下面的 gif 中,您可以看到 Vector3
字段在 Transform
和我的 MonoBehaviour
的检查器中的行为方式的区别。
这个Transform
连一个CustomEditor
我也是用EditorGUILayout.Vector3Field()
写的。
[CustomEditor(typeof(Transform), true)]
[CanEditMultipleObjects]
public class AdvancedTransformEditor : Editor
{
//Unity's built-in editor
private Editor _defaultEditor;
private Transform _transform;
private void OnEnable()
{
//When this inspector is created, also create the built-in inspector
_defaultEditor = CreateEditor(targets, Type.GetType("UnityEditor.TransformInspector, UnityEditor"));
_transform = target as Transform;
}
private void OnDisable()
{
//When OnDisable is called, the default editor we created should be destroyed to avoid memory leakage.
//Also, make sure to call any required methods like OnDisable
var disableMethod = _defaultEditor.GetType().GetMethod("OnDisable", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (disableMethod != null) disableMethod.Invoke(_defaultEditor, null);
DestroyImmediate(_defaultEditor);
}
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Local Space", EditorStyles.boldLabel);
_defaultEditor.OnInspectorGUI();
serializedObject.Update();
//Show World Space Transform
EditorGUILayout.Space();
EditorGUILayout.LabelField("World Space", EditorStyles.boldLabel);
_transform.position = EditorGUILayout.Vector3Field("Position", _transform.position);
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.Vector3Field("Rotation", _transform.eulerAngles);
EditorGUILayout.Vector3Field("Scale", _transform.lossyScale);
EditorGUI.EndDisabledGroup();
serializedObject.ApplyModifiedProperties();
}
}
它只有在有 _defaultEditor.OnInspectorGUI();
时才有效,所以 Unity 的原始编辑器中的 Transform
组件必须做一些不同的事情。
当我尝试在任何其他 CustomEditor
中对 MonoBehaviour
// without a CustomEditor
public class Example : MonoBehaviour
{
public Vector3 example;
}
和
// Width the custom editor
public class ExampleMinWidth : MonoBehaviour
{
public Vector3 example;
}
[CustomEditor(typeof(ExampleMinWidth))]
public class ExampleMinWidthEditor : Editor
{
private SerializedProperty example;
private void OnEnable()
{
example = serializedObject.FindProperty("exmaple");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value);
// I tried both also simply using a PropertyField
//EditorGUILayout.PropertyField(example);
serializedObject.ApplyModifiedProperties();
}
}
或跳过 AdvancedTransformEditor
中的 _defaultEditor.OnInspectorGUI();
行 Vector3
字段会折叠到特定的 Inspector 宽度。
如何让我的字段获得与 Transform
组件相同的行为 - 不折叠但保持在同一行?
更新
我用
GUILayout.MinWidth()
试过了,但这并没有改变任何东西。按照提示我也试过了
example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value, GUILayout.ExpandHeight(false));
(也适用于
PropertyField()
)但这并没有改变任何东西。而且只是为了尝试我也用
ExpandWidth(false)
...结果不是很令人满意:D我什至尝试了
GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight)
但这使得字段仍然折叠但是 "bload"/overdraw 到下面的字段中。
Unity3d 有其 source code available on GitHub, where you can see the Transform 组件实现。
TransformInspector.cs:
/ Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using UnityEngine;
namespace UnityEditor
{
[CustomEditor(typeof(Transform))]
[CanEditMultipleObjects]
internal class TransformInspector : Editor
{
SerializedProperty m_Position;
SerializedProperty m_Scale;
TransformRotationGUI m_RotationGUI;
class Contents
{
public GUIContent positionContent = EditorGUIUtility.TrTextContent("Position", "The local position of this GameObject relative to the parent.");
public GUIContent scaleContent = EditorGUIUtility.TrTextContent("Scale", "The local scaling of this GameObject relative to the parent.");
public string floatingPointWarning = LocalizationDatabase.GetLocalizedString("Due to floating-point precision limitations, it is recommended to bring the world coordinates of the GameObject within a smaller range.");
}
static Contents s_Contents;
public void OnEnable()
{
m_Position = serializedObject.FindProperty("m_LocalPosition");
m_Scale = serializedObject.FindProperty("m_LocalScale");
if (m_RotationGUI == null)
m_RotationGUI = new TransformRotationGUI();
m_RotationGUI.OnEnable(serializedObject.FindProperty("m_LocalRotation"), EditorGUIUtility.TrTextContent("Rotation", "The local rotation of this GameObject relative to the parent."));
}
public override void OnInspectorGUI()
{
if (s_Contents == null)
s_Contents = new Contents();
if (!EditorGUIUtility.wideMode)
{
EditorGUIUtility.wideMode = true;
EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
}
serializedObject.Update();
Inspector3D();
// Warning if global position is too large for floating point errors.
// SanitizeBounds function doesn't even support values beyond 100000
Transform t = target as Transform;
Vector3 pos = t.position;
if (Mathf.Abs(pos.x) > 100000 || Mathf.Abs(pos.y) > 100000 || Mathf.Abs(pos.z) > 100000)
EditorGUILayout.HelpBox(s_Contents.floatingPointWarning, MessageType.Warning);
serializedObject.ApplyModifiedProperties();
}
private void Inspector3D()
{
EditorGUILayout.PropertyField(m_Position, s_Contents.positionContent);
m_RotationGUI.RotationField();
EditorGUILayout.PropertyField(m_Scale, s_Contents.scaleContent);
}
}
}
if (!EditorGUIUtility.wideMode)
{
EditorGUIUtility.wideMode = true;
EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
}
EditorGUIUtility.wideMode 做两件事:Returns 编辑器当前是否是 widemode 和 set 此组件/下一行的编辑器是否应该像在 widemode 下一样工作。所以他们只是强制他们的字段在宽模式下仅 "be"。
之后需要使用 "fixed" EditorGUIUtility.labelWidth 即减少 3
Vectror3
字段在宽模式下的宽度(Unity 使用 212)