简体   繁体   English

如何在CustomPropertyDrawer中设置SerializedProperty.propertyType

[英]How to set SerializedProperty.propertyType in a CustomPropertyDrawer

I am using these two libraries: 我正在使用这两个库:

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 )类-因此使用默认抽屉-它的行为与QuaternionVector4的默认抽屉完全一样:

在此处输入图片说明

  • It has a label and foldout in the first line 第一行有标签和折页
  • fields/content are/is drawn below and only if the property is folded out 字段/内容绘制在下方,且仅在属性折叠后

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 : 另外,您可以做的是更改SceneReferencePropertyDrawer以反映例如Quaternion的行为:

  • Add an EditorGUI.Foldout with the label which changes the property.isExpaned value 添加带有用于更改property.isExpaned值的标签的EditorGUI.Foldout
  • Move any content one line below (and optionally intended) 将任何内容移到下面一行(并且可以选择移动)
  • Add one line to the property height and a condition for 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.

相关问题 如何确定PropertyType是否为外键 - How to determine if a PropertyType is foreign key 如何判断 SerializedProperty 是否是 Unity 中数组的一部分? - How to tell if a SerializedProperty is part of an array in Unity? 如何在WPF中获取索引属性的PropertyType - How to get the PropertyType of indexed property in WPF 如何将json反序列化为PropertyType? - How do I deserialize json into PropertyType? 反思,如何获取PropertyType值并转换为IEnumerable - Reflection, how to get the PropertyType value and convert to IEnumerable 如何强制 Unity 的 SerializedProperty 调用 OnValidate 回调? - How to force Unity's SerializedProperty to call OnValidate callback? Unity Editor Scripting:如何以编程方式更新 CustomEditor SerializedProperty? - Unity Editor Scripting: How to update a CustomEditor SerializedProperty programmatically? 反射:获取/设置属性的PropertyType的属性的值 - Reflection: Get/Set Value of Property's PropertyType's Property 给定PropertyInfo.PropertyType如何将PropertyInfo.GetValue()强制转换为该类型 - Given PropertyInfo.PropertyType how to cast PropertyInfo.GetValue() to that type 如何动态使用PropertyType反射属性来创建相应的类型函数&lt;&gt;? - How to dynamically use the PropertyType reflection attribute to create a respective typed Function<>?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM