[英]How to set SerializedProperty.propertyType in a CustomPropertyDrawer
I am using these two libraries: 我正在使用这两个库:
Unity-SerializableDictionary: https://github.com/starikcetin/Unity-SerializableDictionary Unity-SerializableDictionary: https : //github.com/starikcetin/Unity-SerializableDictionary
Unity Scene Reference: https://github.com/starikcetin/unity-scene-reference Unity场景参考: https : //github.com/starikcetin/unity-scene-reference
Basically, the serializable dictionary looks at the propertyType to determine if the property can be expanded or not, with the following check: 基本上,可序列化的字典查看propertyType以确定属性是否可以扩展,并进行以下检查:
static bool CanPropertyBeExpanded(SerializedProperty property)
{
switch(property.propertyType)
{
case SerializedPropertyType.Generic:
case SerializedPropertyType.Vector4:
case SerializedPropertyType.Quaternion:
return true;
default:
return false;
}
}
However, it appears that Scene Reference is registered as an expandable property even though it isn't. 但是,似乎场景参考已注册为可扩展属性,即使未注册。 This is because -apparently- Unity registers it as of type
Generic
. 这是因为-apparently- Unity将其注册为
Generic
类型。
I can solve this simply by setting the SerializedProperty.propertyType
to a more meaningful type, but it is read-only. 我可以通过将
SerializedProperty.propertyType
设置为更有意义的类型来解决此问题,但是它是只读的。
So, how can I set the SerializedProperty.propertyType
of a custom property drawer? 因此,如何设置自定义属性抽屉的
SerializedProperty.propertyType
?
It isn't documented but the type Generic
is automatically assigned for any custom class (like eg SceneReference
). 它没有记录,但是
Generic
类型自动为任何自定义类分配(例如SceneReference
)。 You can NOT change the propertyType
since it is read-only ... and you can't tell the compiler to handle your custom class as something else ... 您不能更改
propertyType
因为它是只读的 ...并且您不能告诉编译器将自定义类作为其他类型来处理...
Even if you could ... what would be a "more meaningful type"? 即使你可以......这将是一个“更有意义的类型”? The available types for
SerializedPropertyType
are limited and none of them is more meaningful for a custom class. SerializedPropertyType
的可用类型是有限的,并且它们对于自定义类都没有更有意义的意义。
The main "issue" here is: 这里的主要“问题”是:
The SerializableDictionary
drawer simply assumes that usually if you have a custom ( Generic
) class without a custom PropertyDrawer
- so using the default drawer - it behaves exactly like the default drawer of Quaternion
or Vector4
: SerializableDictionary
抽屉简单地假定,如果您有一个没有自定义PropertyDrawer
的自定义( Generic
)类-因此使用默认抽屉-它的行为与Quaternion
或Vector4
的默认抽屉完全一样:
Since the drawer for SceneReference
doesn't implement this behavior it is drawn on top of the dictionary's key-field. 由于
SceneReference
的抽屉没有实现此行为,因此将其绘制在字典的键字段顶部。
So as simplest fix of course you can simply remove the 因此,作为最简单的修复程序,您只需删除
case SerializedPropertyType.Generic:
so the SceneAsset
(and all other custom classes ) is treated like a normal unfolded field - a matter of taste 因此,将
SceneAsset
(以及所有其他自定义类 )视为正常的展开字段- SceneAsset
品味
Alternatively what you could do about it is change the PropertyDrawer
of SceneReference
to reflect the behavior of eg Quaternion
: 另外,您可以做的是更改
SceneReference
的PropertyDrawer
以反映例如Quaternion
的行为:
EditorGUI.Foldout
with the label which changes the property.isExpaned
value property.isExpaned
值的标签的EditorGUI.Foldout
if(!property.isExpanded)
if(!property.isExpanded)
的条件上添加一行 Might look eg like: 可能看起来像:
// Made these two const btw
private const float PAD_SIZE = 2f;
private const float FOOTER_HEIGHT = 10f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Move this up
EditorGUI.BeginProperty(position, GUIContent.none, property);
{
// Here we add the foldout using a single line height, the label and change
// the value of property.isExpanded
property.isExpanded = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, lineHeight), property.isExpanded, label);
// Now you want to draw the content only if you unfold this property
if (property.isExpanded)
{
// Optional: Indent the content
//EditorGUI.indentLevel++;
//{
// reduce the height by one line and move the content one line below
position.height -= lineHeight;
position.y += lineHeight;
var sceneAssetProperty = GetSceneAssetProperty(property);
// Draw the Box Background
position.height -= FOOTER_HEIGHT;
GUI.Box(EditorGUI.IndentedRect(position), GUIContent.none, EditorStyles.helpBox);
position = boxPadding.Remove(position);
position.height = lineHeight;
// Draw the main Object field
label.tooltip = "The actual Scene Asset reference.\nOn serialize this is also stored as the asset's path.";
var sceneControlID = GUIUtility.GetControlID(FocusType.Passive);
EditorGUI.BeginChangeCheck();
{
// removed the label here since we already have it in the foldout before
sceneAssetProperty.objectReferenceValue = EditorGUI.ObjectField(position, sceneAssetProperty.objectReferenceValue, typeof(SceneAsset), false);
}
var buildScene = BuildUtils.GetBuildScene(sceneAssetProperty.objectReferenceValue);
if (EditorGUI.EndChangeCheck())
{
// If no valid scene asset was selected, reset the stored path accordingly
if (buildScene.scene == null) GetScenePathProperty(property).stringValue = string.Empty;
}
position.y += paddedLine;
if (!buildScene.assetGUID.Empty())
{
// Draw the Build Settings Info of the selected Scene
DrawSceneInfoGUI(position, buildScene, sceneControlID + 1);
}
// Optional: If enabled before reset the indentlevel
//}
//EditorGUI.indentLevel--;
}
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var sceneAssetProperty = GetSceneAssetProperty(property);
// Add an additional line and check if property.isExpanded
var lines = property.isExpanded ? sceneAssetProperty.objectReferenceValue != null ? 3 : 2 : 1;
// If this oneliner is confusing you - it does the same as
//var line = 3; // Fully expanded and with info
//if(sceneAssetProperty.objectReferenceValue == null) line = 2;
//if(!property.isExpanded) line = 1;
return boxPadding.vertical + lineHeight * lines + PAD_SIZE * (lines - 1) + FOOTER_HEIGHT;
}
Now it looks like eg 现在看起来像
[Serializable]
public class TestDict : SerializableDictionary<string, SceneReference> { }
public class Example : MonoBehaviour
{
public SceneReference NormalReference;
public TestDict DictExample = new TestDict();
}
Imagine a class like this 想像这样的课程
public class Test
{
public string stringProperty;
}
Now, trying to set propertyType is basically like trying to tell the compiler to change the property type on the class, which is not possible, cause its already wrote down as 'string'. 现在,尝试设置propertyType基本上就像是试图告诉编译器更改类的属性类型,这是不可能的,因为它已被记录为“字符串”。
What you could do is 你能做的是
static bool CanPropertyBeExpanded(SerializedProperty property)
{
float height = EditorGUI.GetPropertyHeight(property);
// Property expandable if its height is twice the single line height.
return height >= EditorGUIUtility.singleLineHeight * 2;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.