平时我们在搭建一个界面后都会给这个界面添加一个界面脚本,一般情况下都是普通的MonoBehaviour的。
此时脚本内定义的参数可以通过public或者特性[SerializeField]显示在inspector面板内。
但有时我们可能希望在面板上加一个按钮,然后能在编辑器模式下点击这个按钮就会执行脚本内的某个方法,此时就需要自定义这个面板。
代码如下示例:
普通界面脚本:
该脚本内有两个列表:templateDatas存储了实例的数据,templates存储了创建的实例对象
以及一些初始化的方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 东/西部概况界面
/// </summary>
public class GeneralSituation : MonoBehaviour
{
/// <summary>
/// 示例物体
/// </summary>
private Template template;
/// <summary>
/// 显示区域
/// </summary>
private Transform content;
/// <summary>
/// 实例列表
/// </summary>
private List<Template> templates = new List<Template>();
/// <summary>
/// 实例数据列表
/// </summary>
[SerializeField]
private List<TemplateData> templateDatas = new List<TemplateData>();
/// <summary>
/// 初始化实例
/// </summary>
public void InitTemplates()
{
}
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
if(template == null)
{
template = this.transform.Find("Template").GetComponent<Template>();
}
if(content == null)
{
content = this.transform.Find("显示列表/Viewport/Content");
}
}
}
Template与TemplateData数据脚本:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 概况界面实例
/// </summary>
public class Template : MonoBehaviour
{
/// <summary>
/// 标签
/// </summary>
[SerializeField]
private Text title;
/// <summary>
/// 值
/// </summary>
[SerializeField]
private Text value;
/// <summary>
/// 字体颜色
/// </summary>
[SerializeField]
private Color color;
/// <summary>
/// 设置标签内容
/// </summary>
/// <param name="title"></param>
public void SetTitle(string title)
{
this.title.text = title;
this.title.color = color;
}
/// <summary>
/// 设置值
/// </summary>
/// <param name="value"></param>
public void SetValue(string value)
{
this.value.text = value;
this.value.color = color;
}
/// <summary>
/// 设置颜色
/// </summary>
/// <param name="color"></param>
public void SetColor(Color color)
{
this.color = color;
this.title.color = color;
this.value.color = color;
}
/// <summary>
/// 获取标签内容
/// </summary>
/// <returns></returns>
public string GetTitle()
{
return this.title.text;
}
}
/// <summary>
/// 实例数据
/// </summary>
[Serializable]
public class TemplateData
{
[SerializeField]
public string title;
[SerializeField]
public string value;
[SerializeField]
public Color color;
public TemplateData(string title, string value, Color color)
{
this.title = title;
this.value = value;
this.color = color;
}
}
界面编辑器脚本:
该脚本继承Editor,加上特性[CustomEditor(typeof(具体界面类))],然后实现OnInspectorGUI()方法即可自定义inspector显示面板,效果图如下
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
/// <summary>
/// 东/西部概况界面编辑器
/// </summary>
[CustomEditor(typeof(GeneralSituation))]
public class GeneralSituationEditor : Editor
{
GeneralSituation ui;
GUILayoutOption[] options = new GUILayoutOption[] { GUILayout.Width(100f) };
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
ui = (GeneralSituation)this.target;
ui.Init();
GUILayout.BeginVertical();
//若设置了参数的显示效果,此处可注释掉
for (int i = 0; i < ui.templateDatas.Count; i++)
{
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField("标题:", new GUILayoutOption[] { GUILayout.Width(30f) });
ui.templateDatas[i].title = EditorGUILayout.TextField(ui.templateDatas[i].title, options);
EditorGUILayout.LabelField("值:", new GUILayoutOption[] { GUILayout.Width(30f) });
ui.templateDatas[i].value = EditorGUILayout.TextField(ui.templateDatas[i].value, options);
EditorGUILayout.LabelField("颜色:", new GUILayoutOption[] { GUILayout.Width(30f) });
ui.templateDatas[i].color = EditorGUILayout.ColorField(ui.templateDatas[i].color, options);
if (GUILayout.Button("-", new GUILayoutOption[] { GUILayout.Width(20f) }))
{
ui.templateDatas.Remove(ui.templateDatas[i]);
}
GUILayout.EndHorizontal();
}
if (GUILayout.Button("+", new GUILayoutOption[] { GUILayout.Width(20f) }))
{
ui.templateDatas.Add(new TemplateData("", "", Color.white));
}
//可注释
if (GUILayout.Button("确定", new GUILayoutOption[] { GUILayout.Width(100f) }))
{
ui.InitTemplates();
}
GUILayout.EndVertical();
}
}
效果图:
若要修改参数在inspector面板显示,需要新建一个脚本继承PropertyDrawer,然后添加特性[CustomPropertyDrawer(typeof(参数类名))],然后实现OnGUI()方法,示例如下
TemplateDataDrawer:
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
/// <summary>
/// 实例数据编辑器
/// </summary>
[CustomPropertyDrawer(typeof(TemplateData))]
public class TemplateDataDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
//FocusType.Passive 使用Tab键切换时不会被选中,FocusType.Keyboard 使用Tab键切换时会被选中
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
//不让indentLevel层级影响到同一行的绘制,因为PropertyDrawer在很多地方都有可能被用到,可能出现嵌套使用
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
//定义各数据显示区域位置与大小
var titleRect = new Rect(position.x, position.y,100, position.height);
var valueRect = new Rect(position.x + 105, position.y, 50, position.height);
var colorRect = new Rect(position.x + 160, position.y, 50, position.height);
//设置参数对应位置与大小
EditorGUI.PropertyField(titleRect, property.FindPropertyRelative("title"), GUIContent.none);
EditorGUI.PropertyField(valueRect, property.FindPropertyRelative("value"), GUIContent.none);
EditorGUI.PropertyField(colorRect, property.FindPropertyRelative("color"), GUIContent.none);
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
效果如图:
两者结合即可实现inspector面板的自定义效果 ,当然也可以分开使用