-
-
Save t0chas/34afd1e4c9bc28649311 to your computer and use it in GitHub Desktop.
using UnityEngine; | |
using UnityEditor; | |
using UnityEditorInternal; | |
using System.Collections.Generic; | |
using UnityEditor.AnimatedValues; | |
[CustomEditor(typeof(UnityEngine.Object), true, isFallback = true)] | |
[CanEditMultipleObjects] | |
public class CustomEditorBase : Editor | |
{ | |
private Dictionary<string, ReorderableListProperty> reorderableLists; | |
protected virtual void OnEnable() | |
{ | |
this.reorderableLists = new Dictionary<string, ReorderableListProperty>(10); | |
} | |
~CustomEditorBase() | |
{ | |
this.reorderableLists.Clear(); | |
this.reorderableLists = null; | |
} | |
public override void OnInspectorGUI() | |
{ | |
EditorGUILayout.LabelField("Custom Editor", EditorStyles.centeredGreyMiniLabel); | |
Color cachedGuiColor = GUI.color; | |
serializedObject.Update(); | |
var property = serializedObject.GetIterator(); | |
var next = property.NextVisible(true); | |
if (next) | |
do | |
{ | |
GUI.color = cachedGuiColor; | |
this.HandleProperty(property); | |
} while (property.NextVisible(false)); | |
serializedObject.ApplyModifiedProperties(); | |
} | |
protected void HandleProperty(SerializedProperty property) | |
{ | |
//Debug.LogFormat("name: {0}, displayName: {1}, type: {2}, propertyType: {3}, path: {4}", property.name, property.displayName, property.type, property.propertyType, property.propertyPath); | |
bool isdefaultScriptProperty = property.name.Equals("m_Script") && property.type.Equals("PPtr<MonoScript>") && property.propertyType == SerializedPropertyType.ObjectReference && property.propertyPath.Equals("m_Script"); | |
bool cachedGUIEnabled = GUI.enabled; | |
if (isdefaultScriptProperty) | |
GUI.enabled = false; | |
//var attr = this.GetPropertyAttributes(property); | |
if (property.isArray && property.propertyType != SerializedPropertyType.String) | |
this.HandleArray(property); | |
else | |
EditorGUILayout.PropertyField(property, property.isExpanded); | |
if (isdefaultScriptProperty) | |
GUI.enabled = cachedGUIEnabled; | |
} | |
protected void HandleArray(SerializedProperty property) | |
{ | |
var listData = this.GetReorderableList(property); | |
listData.IsExpanded.target = property.isExpanded; | |
if ((!listData.IsExpanded.value && !listData.IsExpanded.isAnimating) || (!listData.IsExpanded.value && listData.IsExpanded.isAnimating)) | |
{ | |
EditorGUILayout.BeginHorizontal(); | |
property.isExpanded = EditorGUILayout.ToggleLeft(string.Format("{0}[]", property.displayName), property.isExpanded, EditorStyles.boldLabel); | |
EditorGUILayout.LabelField(string.Format("size: {0}", property.arraySize)); | |
EditorGUILayout.EndHorizontal(); | |
} | |
else { | |
if (EditorGUILayout.BeginFadeGroup(listData.IsExpanded.faded)) | |
listData.List.DoLayoutList(); | |
EditorGUILayout.EndFadeGroup(); | |
} | |
} | |
protected object[] GetPropertyAttributes(SerializedProperty property) | |
{ | |
return this.GetPropertyAttributes<PropertyAttribute>(property); | |
} | |
protected object[] GetPropertyAttributes<T>(SerializedProperty property) where T : System.Attribute | |
{ | |
System.Reflection.BindingFlags bindingFlags = System.Reflection.BindingFlags.GetField | |
| System.Reflection.BindingFlags.GetProperty | |
| System.Reflection.BindingFlags.IgnoreCase | |
| System.Reflection.BindingFlags.Instance | |
| System.Reflection.BindingFlags.NonPublic | |
| System.Reflection.BindingFlags.Public; | |
if (property.serializedObject.targetObject == null) | |
return null; | |
var targetType = property.serializedObject.targetObject.GetType(); | |
var field = targetType.GetField(property.name, bindingFlags); | |
if (field != null) | |
return field.GetCustomAttributes(typeof(T), true); | |
return null; | |
} | |
private ReorderableListProperty GetReorderableList(SerializedProperty property) | |
{ | |
ReorderableListProperty ret = null; | |
if (this.reorderableLists.TryGetValue(property.name, out ret)) | |
{ | |
ret.Property = property; | |
return ret; | |
} | |
ret = new ReorderableListProperty(property); | |
this.reorderableLists.Add(property.name, ret); | |
return ret; | |
} | |
#region Inner-class ReorderableListProperty | |
private class ReorderableListProperty | |
{ | |
public AnimBool IsExpanded { get; private set; } | |
/// <summary> | |
/// ref http://va.lent.in/unity-make-your-lists-functional-with-reorderablelist/ | |
/// </summary> | |
public ReorderableList List { get; private set; } | |
private SerializedProperty _property; | |
public SerializedProperty Property | |
{ | |
get { return this._property; } | |
set | |
{ | |
this._property = value; | |
this.List.serializedProperty = this._property; | |
} | |
} | |
public ReorderableListProperty(SerializedProperty property) | |
{ | |
this.IsExpanded = new AnimBool(property.isExpanded); | |
this.IsExpanded.speed = 1f; | |
this._property = property; | |
this.CreateList(); | |
} | |
~ReorderableListProperty() | |
{ | |
this._property = null; | |
this.List = null; | |
} | |
private void CreateList() | |
{ | |
bool dragable = true, header = true, add = true, remove = true; | |
this.List = new ReorderableList(this.Property.serializedObject, this.Property, dragable, header, add, remove); | |
this.List.drawHeaderCallback += rect => this._property.isExpanded = EditorGUI.ToggleLeft(rect, this._property.displayName, this._property.isExpanded, EditorStyles.boldLabel); | |
this.List.onCanRemoveCallback += (list) => { return this.List.count > 0; }; | |
this.List.drawElementCallback += this.drawElement; | |
this.List.elementHeightCallback += (idx) => { return Mathf.Max(EditorGUIUtility.singleLineHeight, EditorGUI.GetPropertyHeight(this._property.GetArrayElementAtIndex(idx), GUIContent.none, true)) + 4.0f; }; | |
} | |
private void drawElement(Rect rect, int index, bool active, bool focused) | |
{ | |
if (this._property.GetArrayElementAtIndex(index).propertyType == SerializedPropertyType.Generic) | |
{ | |
EditorGUI.LabelField(rect, this._property.GetArrayElementAtIndex(index).displayName); | |
} | |
//rect.height = 16; | |
rect.height = EditorGUI.GetPropertyHeight(this._property.GetArrayElementAtIndex(index), GUIContent.none, true); | |
rect.y += 1; | |
EditorGUI.PropertyField(rect, this._property.GetArrayElementAtIndex(index), GUIContent.none, true); | |
this.List.elementHeight = rect.height + 4.0f; | |
} | |
} | |
#endregion | |
} |
#pragma strict | |
var myInt : int = 5; | |
var myFloat: float = 10.56; | |
public var players : GameObject[]; | |
public var floats : float[]; | |
public var numbers : int[]; | |
public var vectors : Vector3[]; | |
function Start () { | |
} | |
function Update () { | |
} |
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
//using System; | |
[System.Flags] | |
public enum Stuff{ | |
Coke = 1 << 0, | |
Hamburguer = 1 << 1, | |
Pizza = 1 << 2, | |
Hotdog = 1 << 3, | |
Pepsi = 1 << 4, | |
Beer = 1 << 5, | |
BuffaloWings = 1 << 6, | |
IceCream = 1 << 7, | |
} | |
[System.Serializable] | |
public struct SomeOtherData | |
{ | |
public int aNumber; | |
[Range(0f, 1f)] | |
public float anotherNumber; | |
public Vector3 position; | |
} | |
public class Tester : MonoBehaviour { | |
public int aNumber; | |
public int AFloat; | |
[Range(0f, 100f)] | |
public float AFloatRangeAttr; | |
public string aString; | |
public int[] aNumerArray; | |
public float[] aFloatArray; | |
[Range(0.0f, 100.0f)] | |
public float[] anotherFloatArray; | |
[SerializeField] | |
private List<Stuff> privateListOfStuff; | |
[SerializeField] | |
private SomeOtherData NestedData; | |
[SerializeField] | |
private AudioMixerClip mixerClip; | |
[SerializeField] | |
private AudioMixerClip[] mixerClips; | |
} |
@Casey-Hofland, I would also like to see your final edit, as it's not clear what to do with original line 59 once you start pulling out AnimBool and AnimatedValues.
@t0chas, this doesn't work too well with recent version of Unity.
- "Element 0, Element 1, etc" text is displayed in grey behind the elements themselves: https://i.imgur.com/YecUs7z.png
- There is a big delay when expanding/collapsing the array.
- Dragging objects to add new elements is not working.
- Nested arrays not working.
I think the main flaw is that you shouldn't use Custom Inspector to solve this problem, but PropertyDrawer instead. I know they are harder to work with but it's the only way to do it properly.
How can I remove the foldout in the elements? I find it slows me down having to expand them and it looks kinda bad. I removed the expand button at the top but I can't find anything in the code about the foldouts. The regular reorderable lists don't use these so I assume you're either using something else or have manually added them. Any ideas?
@t0chas, this doesn't work too well with recent version of Unity.
- "Element 0, Element 1, etc" text is displayed in grey behind the elements themselves: https://i.imgur.com/YecUs7z.png
- There is a big delay when expanding/collapsing the array.
- Dragging objects to add new elements is not working.
- Nested arrays not working.
I think the main flaw is that you shouldn't use Custom Inspector to solve this problem, but PropertyDrawer instead. I know they are harder to work with but it's the only way to do it properly.
I recommend use https://github.com/SubjectNerd-Unity/ReorderableInspector It does solve the issue with folding and provides many more features.
@Casey-Hofland I tried to put in your code changes, and the list doesn't work. The part when you remove the AnimBool is where it all goes wrong. Can you please add a link or comment the actual code that you made. I really don't like clicking a bool to open my list ;). Thank you.