728x90
반응형
1. Property Drawer이란?
Unity에서 개발을 하다가 보면 Editor에 UI를 커스텀하고 싶을 때가 있다.
그럴 때 사용할 수 있는 것이 Property Drawer이다.
Property Drawer를 상속 받아서 특정 클래스가 Inspector에서 Serialize 되는 방식을 설정할 수 있다.
2. Code
다음은 "Event"란 class를 상속 받는 모든 class를 Reflection으로 받아와서 (private void InitializeClassInfos)
OnGui 에서 Drop Down menu를 정의하여 class 선택지를 주고
CreateSubClassInstance에서 Reflection으로 그 subclass의 객체를 생성하여 담아준다.
Editor에서 MonoBehaviour Class에서 has-a Class의 Type을 Editor에서 딸깍으로 변경할 수 있게 해준다.
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System;
using System.Reflection;
[CustomPropertyDrawer(typeof(Event), true)]
public class EventDrawer : PropertyDrawer
{
//Class Infos
private static Dictionary<string, Type> classInfos = new Dictionary<string, Type>();
//Drop Down names
private static string[] classNames = null;
//Initializer
private void InitializeClassInfos()
{
Assembly assembly = Assembly.GetAssembly(typeof(Event));
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
if (!type.IsAbstract && type.IsSubclassOf(typeof(Event))){
classInfos.Add(type.Name, type);
}
}
classNames = new string[classInfos.Count];
int index = 0;
foreach (string tuple in classInfos.Keys)
{
classNames[index] = tuple;
index++;
}
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (classNames == null)
{
InitializeClassInfos();
}
//initial gui setting
EditorGUI.BeginProperty(position, label, property);
// draw default label
EditorGUI.LabelField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), label);
// draw drop down menu
Rect dropdownRect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight);
int selectedIndex = GetClassIndex(property);
int newIndex = EditorGUI.Popup(dropdownRect, "Select Subclass", selectedIndex, classNames);
// if selected class is change
if (newIndex != selectedIndex)
{
CreateSubclassInstance(property, newIndex);
}
// draw selected class
EditorGUI.PropertyField(new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * 2, position.width, position.height), property, true);
//end gui setting
EditorGUI.EndProperty();
}
// get current class index
private int GetClassIndex(SerializedProperty property)
{
if (property.managedReferenceValue == null) return -1;
string targetName = property.managedReferenceValue.GetType().ToString();
int index = 0;
foreach (string name in classNames)
{
if (name.Equals(targetName))
{
return index;
}
index++;
}
return -1; //default value
}
// set property to instance of selected class
private void CreateSubclassInstance(SerializedProperty property, int index)
{
property.managedReferenceValue = Activator.CreateInstance(classInfos[classNames[index]]);
property.serializedObject.ApplyModifiedProperties();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
// default height
float height = EditorGUIUtility.singleLineHeight * 3 + EditorGUIUtility.standardVerticalSpacing * 2;
SerializedProperty iterator = property.Copy();
// add child properties heights
while (iterator.NextVisible(true))
{
if (iterator.propertyPath.StartsWith(property.propertyPath) && iterator.propertyPath != property.propertyPath)
{
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
}
else
{
break;
}
}
return height;
}
}
728x90
반응형
'Unity' 카테고리의 다른 글
Drag and Drop in Unity (0) | 2023.03.20 |
---|