七、编辑器开发之PropertyDrawer

2022-08-29 15:37:08 浏览数 (1)

PropertyDrawer允许我们控制一个属性的Inspector检视面板的GUI如何绘制。

首先看几个Unity中内置的PropertyDrawers:

代码语言:javascript复制
[Range(0, 20)]
public int intValue = 10;

[Header("名称")]
public string nameStr;

[SerializeField]
private float floatValue = 10f;

如图所示,Range可以限制intValue的取值范围0~20,Header可以给字段做一些描述或备注,SerializeField允许我们讲一个Private私有字段同Public字段一样显示在Inspector检视面板上。

那么如何自定义一个PropertyDrawer?以一个Time特性为例:

代码语言:javascript复制
[Time]
public float time = 473.35f;

我们希望将一个float类型的描述时间的字段在Inspector面板上以00:00时间格式进行显示:

首先先定义Time特性:

代码语言:javascript复制
using UnityEngine;

namespace SK.Framework
{
    /// <summary>
    /// 时间特性
    /// </summary>
    public sealed class TimeAttribute : PropertyAttribute
    {
        /// <summary>
        /// 显示小时
        /// </summary>
        public readonly bool displayHours;
        /// <summary>
        /// 显示毫秒
        /// </summary>
        public readonly bool displayMillseconds;
        /// <summary>
        /// 构造函数 
        /// </summary>
        /// <param name="displayHours">显示小时</param>
        /// <param name="displayMillseconds">显示毫秒</param>
        public TimeAttribute (bool displayHours = false, bool displayMillseconds = false)
        {
            this.displayHours = displayHours;
            this.displayMillseconds = displayMillseconds;
        }
    }
}

有了TimeAttribute后,我们来自定义它如何在Inspector上进行绘制:

需要在Editor文件夹中创建TimeDrawer类,引入UnityEditor命名空间并继承PropertyDrawer

然后Override重写OnGUI方法来实现绘制,GetPropertyHeight用来定义绘制属性的高度

代码语言:javascript复制
using System;
using UnityEngine;
using UnityEditor;

namespace SK.Framework
{
    /// <summary>
    /// 时间特性绘制
    /// </summary>
    [CustomPropertyDrawer(typeof(TimeAttribute))]
    public sealed class TimeDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            if(property.propertyType == SerializedPropertyType.Float)
            {
                property.floatValue = EditorGUI.FloatField(new Rect(position.x, position.y, position.width * 0.6f, position.height), label, property.floatValue);
                EditorGUI.LabelField(new Rect(position.x   position.width * 0.6f, position.y, position.width * 0.4f, position.height), GetTimeFormat(property.floatValue));
            }
            else
            {
                EditorGUI.HelpBox(new Rect(position.x, position.y, position.width, position.height), "只支持float类型属性", MessageType.Error);
            }
        }

        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            return base.GetPropertyHeight(property, label);
        }

        private string GetTimeFormat(float secondsTime)
        {
            TimeAttribute ta = attribute as TimeAttribute;
            //显示小时不显示毫秒
            if (ta.displayHours && !ta.displayMillseconds)
            {
                int l = Convert.ToInt32(secondsTime);
                int hours = l / 3600;
                int minutes = l % 3600 / 60;
                int seconds = l % 3600 % 60;
                return string.Format("({0:D2}:{1:D2}:{2:D2} [hh:mm:ss])", hours, minutes, seconds);
            }
            //显示毫秒不显示小时
            else if(!ta.displayHours && ta.displayMillseconds)
            {
                int l = Convert.ToInt32(secondsTime * 1000);
                int minutes = l / 60000;
                int seconds = l % 60000 / 1000;
                int millSeconds = l % 60000 % 1000;
                return string.Format("({0:D2}:{1:D2}.{2:D3} [mm:ss.fff)]", minutes, seconds, millSeconds);
            }
            //既显示小时也显示毫秒
            else if (ta.displayHours && ta.displayMillseconds)
            {
                int l = Convert.ToInt32(secondsTime * 1000);
                int hours = l / 3600000;
                int minutes = l % 3600000 / 60000;
                int seconds = l % 3600000 % 60000 / 1000;
                int millSeconds = l % 3600000 % 60000 % 1000;
                return string.Format("({0:D2}:{1:D2}:{2:D2}.{3:D3} [hh:mm:ss.fff)]", hours, minutes, seconds, millSeconds);
            }
            //既不显示小时也不显示毫秒
            else
            {
                int l = Convert.ToInt32(secondsTime);
                int minutes = l / 60;
                int seconds = l % 60;
                return string.Format("({0:D2}:{1:D2}) [mm:ss]", minutes, seconds);
            }
        }
    }
}

TimeAttribute可以控制是否显示小时、是否显示毫秒:

代码语言:javascript复制
[Time(true, true)]
public float time1 = 473.35f;
[Time(true, false)]
public float time2 = 473.35f;
[Time(false, true)]
public float time3 = 473.35f;
[Time]
public float time4 = 473.35f;
[Time]
public int time5 = 0;
gui

0 人点赞