白泽图

  • 文章
    • Unity渲染
    • Unity项目开发
    • 工具
    • 数学
    • 算法
    • 网站搭建
    • 网络&操作系统
蒋程个人博客
互联网技术经验总结&分享
  1. 首页
  2. Unity项目开发
  3. 正文

如何使用EditorGUILayout编辑PropertyDrawer

2022-05-29 1656点热度 0人点赞 0条评论

Unity提供PropertyDrawer使我们可以编写指定类型数据的Inspector,比如我们重写Vector3属性的Inspector面板,那么任何使用Vector3的类,其中Vector3类型的序列化数据在Inspector都会变成我们重写的样式,下面是官方使用PropertyDrawer重写属性的示例代码

// The property drawer class should be placed in an editor script, inside a folder called Editor.

// Tell the RangeDrawer that it is a drawer for properties with the RangeAttribute.
using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(RangeAttribute))]
public class RangeDrawer : PropertyDrawer
{
    // Draw the property inside the given rect
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // First get the attribute since it contains the range for the slider
        RangeAttribute range = attribute as RangeAttribute;

        // Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
        if (property.propertyType == SerializedPropertyType.Float)
            EditorGUI.Slider(position, property, range.min, range.max, label);
        else if (property.propertyType == SerializedPropertyType.Integer)
            EditorGUI.IntSlider(position, property, Convert.ToInt32(range.min), Convert.ToInt32(range.max), label);
        else
            EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
    }
}
// This is not an editor script. The property attribute class should be placed in a regular script file.
using UnityEngine;

public class RangeAttribute : PropertyAttribute
{
    public float min;
    public float max;

    public RangeAttribute(float min, float max)
    {
        this.min = min;
        this.max = max;
    }
}

写一个测试代码

public class JCTest
{
    public int a;
    public RangeAttribute r;
}

通过上面的代码可以看出,如果要使用PropertyDrawer必须使用EditorGUI里的函数,那么如果我们把EditorGUI换成EditorGUILayout,那么我们会得到一个错误

下面解释这个错误是怎么来的

在OnGUI函数中,添加以下两行代码

var evt = UnityEngine.Event.current;
Debug.Log(evt.type);

也就是说OnGUI函数会被调用两次,第一次是Layout,第二次是repaint,在Layout中,Unity会为我们自动计算各组件的坐标位置,然后会在repaint时将组件画出来,这也是为什么所有的EditorGUILayout函数不需要我们手动传入Rect的原因,而上面的示例出错也很好理解,原因是PropertyDrawer的属性只是它的数据(JCTest)的Inspector的一部分,所以在显示PropertyDrawer的属性时由于不知道其他组件的位置,所以也无法计算出在OnGUI函数中使用EditorGUILayout创建的组件位置

解决方法:为JCTest添加Editor代码

[CustomEditor(typeof(JCTest))]
public class TBCAssetInspector : UnityEditor.Editor
{
    public override void OnInspectorGUI()
    {
        EditorGUI.BeginChangeCheck();
        serializedObject.Update();

        SerializedProperty property = serializedObject.GetIterator();
        bool expanded = true;
        while (property.NextVisible(expanded))
        {
            expanded = false;
            if (SkipField(property.propertyPath))
                continue;
            EditorGUILayout.PropertyField(property, true);
        }


        if (EditorGUI.EndChangeCheck())
            serializedObject.ApplyModifiedProperties();
    }

    static bool SkipField(string fieldName)
    {
        return fieldName == "m_Script";
    }
}

此方法虽然解决了EditorGUILayout编辑PropertyDrawer报错的问题,但也使PropertyDrawer失去了意义,所以建议还是使用EditorGUI行进编辑

标签: 暂无
最后更新:2022-05-29

蒋程

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

COPYRIGHT © 2023 白泽图. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

登录
注册|忘记密码?