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;