Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A PropertyDrawer to show a popup field with a generic list of string for your Unity3d attribute
public class MyBehavior : MonoBehaviour {
// This will store the string value
[StringInList("Cat", "Dog")] public string Animal;
// This will store the index of the array value
[StringInList("John", "Jack", "Jim")] public int PersonID;
// Showing a list of loaded scenes
[StringInList(typeof(PropertyDrawersHelper), "AllSceneNames")] public string SceneName;
}
using UnityEditor;
using UnityEngine;
public static class PropertyDrawersHelper {
#if UNITY_EDITOR
public static string[] AllSceneNames()
{
var temp = new List<string>();
foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
{
if (S.enabled)
{
string name = S.path.Substring(S.path.LastIndexOf('/')+1);
name = name.Substring(0,name.Length-6);
temp.Add(name);
}
}
return temp.ToArray();
}
#endif
}
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class StringInList : PropertyAttribute {
public delegate string[] GetStringList();
public StringInList(params string [] list) {
List = list;
}
public StringInList(Type type, string methodName) {
var method = type.GetMethod (methodName);
if (method != null) {
List = method.Invoke (null, null) as string[];
} else {
Debug.LogError ("NO SUCH METHOD " + methodName + " FOR " + type);
}
}
public string[] List {
get;
private set;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(StringInList))]
public class StringInListDrawer : PropertyDrawer {
// Draw the property inside the given rect
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
var stringInList = attribute as StringInList;
var list = stringInList.List;
if (property.propertyType == SerializedPropertyType.String) {
int index = Mathf.Max (0, Array.IndexOf (list, property.stringValue));
index = EditorGUI.Popup (position, property.displayName, index, list);
property.stringValue = list [index];
} else if (property.propertyType == SerializedPropertyType.Integer) {
property.intValue = EditorGUI.Popup (position, property.displayName, property.intValue, list);
} else {
base.OnGUI (position, property, label);
}
}
}
#endif
@Feddas

This comment has been minimized.

Copy link

commented Apr 18, 2018

This is awesome. Thanks for posting this and the run down on coderwall.

I did have a little trouble getting it to work. After reading a forum post I realized the StringInListDrawer class needed to be in a separate file so that the PropertyDrawer is in an Editor folder and the PropertyAttribute (& Helper) is not.

@EduardoSimon

This comment has been minimized.

Copy link

commented Jan 24, 2019

I've have implemented this kind of behaviour by myself, but when I rename the scene asset in the editor window, my serialized property gets lost. I have tried to set up a callback to find if the project's changed, but I cant find a proper way to get the asset that has been changed and check if its one of the loaded scenes. Any help with it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.