{"id":2590,"date":"2022-05-04T10:51:25","date_gmt":"2022-05-04T02:51:25","guid":{"rendered":"https:\/\/www.clonefactor.com\/wordpress\/?p=2590"},"modified":"2022-05-04T10:58:27","modified_gmt":"2022-05-04T02:58:27","slug":"unity3d-unityeditor-%e4%b8%8a%e7%9a%84-drag-and-drop-%e5%af%ab%e6%b3%95","status":"publish","type":"post","link":"https:\/\/www.clonefactor.com\/wordpress\/public\/2590\/","title":{"rendered":"Unity3d : UnityEditor \u4e0a\u7684 Drag and drop \u5beb\u6cd5."},"content":{"rendered":"\n<p>\u501f\u5de5\u4f5c\u4e4b\u4fbf\u89e3\u6c7a\u4e86\u5148\u524d\u60f3\u4e0d\u5230\u7684 Drag and drop \u7684\u5224\u65b7.<\/p>\n<ul>\n<li>\u5229\u7528 Event.Current \u4e0a\u7684 EventType.DragUpdated, DragPerform \u7b49\u6293\u53d6 Drag \u72c0\u614b<\/li>\n<li>\u4f7f\u7528 GUILayoutUtility.GetLastRect() \u53d6\u5f97\u5148\u524d\u7684 list element \u7684\u7e6a\u756b\u5927\u5c0f\u4e26\u8986\u84cb.<\/li>\n<li>\u5206\u62c6\u51fa DragAndDrop.objectReferences (\u9078\u53d6\u7684 Asset list) \u4e26\u653e\u5165 nest \u7d50\u69cb\u7684 struct \u88e1\u9762 (a.k.a: NamedPrefab)<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"384\" height=\"225\" data-id=\"2591\" src=\"https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop.png\" alt=\"\" class=\"wp-image-2591\" srcset=\"https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop.png 384w, https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop-300x176.png 300w, https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop-359x210.png 359w\" sizes=\"auto, (max-width: 384px) 100vw, 384px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"379\" height=\"237\" data-id=\"2594\" src=\"https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop_After.png\" alt=\"\" class=\"wp-image-2594\" srcset=\"https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop_After.png 379w, https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop_After-300x188.png 300w, https:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2022\/05\/DragAndDrop_After-359x224.png 359w\" sizes=\"auto, (max-width: 379px) 100vw, 379px\" \/><\/figure>\n<\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n#if UNITY_EDITOR\nusing UnityEditor;\n#endif\nnamespace Test\n{\n    [CreateAssetMenu]\n    public class PrefabLoader : ScriptableObject\n    {\n        [System.Serializable]\n        public struct NamedPrefab\n        {\n            public GameObject prefab;\n            public string name;\n        }\n        public List&lt;NamedPrefab> m_PrefabList;\n\n        private Dictionary&lt;string, GameObject> m_PrefabDic = null;\n        public Dictionary&lt;string, GameObject> PrefabDic\n        {\n            get\n            {\n                if (m_PrefabDic == null)\n                {\n                    m_PrefabDic = new Dictionary&lt;string, GameObject>(m_PrefabList.Count);\n                    for (int i = 0; i &lt; m_PrefabList.Count; ++i)\n                    {\n                        \/\/ Noted: assume not require duplicate checking.\n                        m_PrefabDic.Add(m_PrefabList[i].name, m_PrefabList[i].prefab);\n                    }\n                }\n                return m_PrefabDic;\n            }\n        }\n    }\n\n#if UNITY_EDITOR\n\n    [CustomEditor(typeof(PrefabLoader), true)]\n    public class PrefabLoaderInspector : Editor\n    {\n        SerializedProperty scriptProp;\n        SerializedProperty prefabListProp;\n        private void OnEnable()\n        {\n            scriptProp = serializedObject.FindProperty(\"m_Script\");\n            prefabListProp = serializedObject.FindProperty(nameof(PrefabLoader.m_PrefabList));\n        }\n\n        public override void OnInspectorGUI()\n        {\n            serializedObject.UpdateIfRequiredOrScript();\n            SerializedProperty iter = serializedObject.GetIterator();\n            iter.NextVisible(true);\n            EditorGUI.BeginDisabledGroup(true);\n            EditorGUILayout.PropertyField(scriptProp, includeChildren: true);\n            EditorGUI.EndDisabledGroup();\n\n            EditorGUI.BeginChangeCheck(); \/\/ ---- change check [optional]\n\n            do\n            {\n                if (scriptProp != null &amp;&amp; iter.propertyPath == scriptProp.propertyPath)\n                {\n                    \/\/ do nothing.\n                }\n                else\n                {\n                    OnDrawProperty(iter);\n                }\n            }\n            while (iter.NextVisible(false));\n\n            if (EditorGUI.EndChangeCheck()) \/\/ ---- change check [optional]\n                serializedObject.ApplyModifiedProperties();\n        }\n\n        private void OnDrawProperty(SerializedProperty property)\n        {\n            if (property.propertyPath == prefabListProp.propertyPath)\n            {\n                EditorGUILayout.PropertyField(property);\n                DragArea(GUILayoutUtility.GetLastRect(), property, NamedPrefabEditorDrawer.CustomDraw);\n            }\n            else\n            {\n                EditorGUILayout.PropertyField(property);\n            }\n        }\n\n        public delegate void InsertProperty(SerializedProperty listProperty, UnityEngine.Object interactObj);\n\n        private void DragArea(Rect area, SerializedProperty property, InsertProperty drawCallback)\n        {\n            Event evt = Event.current;\n            if (evt.type == EventType.Repaint &amp;&amp;\n                DragAndDrop.visualMode == DragAndDropVisualMode.Copy)\n                GUI.Box(area, \"Drag and drop all Skin.\", GUI.skin.window);\n            switch (evt.type)\n            {\n                case EventType.DragUpdated:\n                case EventType.DragPerform:\n                    if (!area.Contains(evt.mousePosition))\n                        return;\n                    DragAndDrop.visualMode = DragAndDropVisualMode.Copy;\n\n                    if (evt.type == EventType.DragPerform)\n                    {\n                        DragAndDrop.AcceptDrag();\n                        if (property.isArray)\n                        {\n                            foreach (UnityEngine.Object obj in DragAndDrop.objectReferences)\n                            {\n                                if (!(obj is GameObject prefab))\n                                    continue;\n                                if (!string.IsNullOrEmpty(prefab.scene.path))\n                                {\n                                    Debug.LogError($\"Scene object {prefab.name} not allow\");\n                                    continue;\n                                }\n                                int last = property.arraySize;\n                                property.InsertArrayElementAtIndex(last);\n                                drawCallback?.Invoke(property.GetArrayElementAtIndex(last), obj);\n                                property.serializedObject.ApplyModifiedProperties();\n                            }\n                        }\n                        else\n                        {\n                            \/\/ Debug.LogError(\"Haven't test\");\n                            var obj = DragAndDrop.objectReferences.GetValue(0) as UnityEngine.Object;\n                            drawCallback?.Invoke(property, obj);\n                        }\n                    }\n                    break;\n                case EventType.MouseUp:\n                    DragAndDrop.PrepareStartDrag();\n                    break;\n            }\n        }\n    }\n\n    [CustomPropertyDrawer(typeof(PrefabLoader.NamedPrefab), true)]\n    public class NamedPrefabEditorDrawer : PropertyDrawer\n    {\n        public static void CustomDraw(SerializedProperty property, UnityEngine.Object interactObj)\n        {\n            \/\/ Debug.Log(listProperty.propertyType);\n            var nameProp = property.FindPropertyRelative(nameof(PrefabLoader.NamedPrefab.name));\n            var prefabProp = property.FindPropertyRelative(nameof(PrefabLoader.NamedPrefab.prefab));\n            nameProp.stringValue = interactObj.name;\n            prefabProp.objectReferenceValue = interactObj;\n            property.serializedObject.ApplyModifiedProperties();\n        }\n\n        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)\n        {\n            \/\/ return base.GetPropertyHeight(property, label);\n            return EditorGUIUtility.singleLineHeight;\n        }\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            EditorGUI.BeginProperty(position, label, property);\n            \/\/ position = EditorGUI.PrefixLabel(position, label);\n            Rect[] rect = { position, position };\n            const float hSpace = 4f;\n            rect[0].width = EditorGUIUtility.labelWidth - hSpace;\n            rect[1].width = rect[1].width - rect[0].width;\n            rect[1].x += rect[0].width + hSpace;\n            SerializedProperty nameProp = property.FindPropertyRelative(nameof(PrefabLoader.NamedPrefab.name));\n            SerializedProperty prefabProp = property.FindPropertyRelative(nameof(PrefabLoader.NamedPrefab.prefab));\n\n            EditorGUI.BeginChangeCheck();\n            string tmp = EditorGUI.TextField(rect[0], nameProp.stringValue);\n            EditorGUI.PropertyField(rect[1], prefabProp, GUIContent.none, false);\n            if (EditorGUI.EndChangeCheck())\n            {\n                if (string.IsNullOrEmpty(tmp) &amp;&amp; prefabProp.objectReferenceValue != null)\n                {\n                    tmp = prefabProp.objectReferenceValue.name;\n                }\n                nameProp.stringValue = tmp;\n                property.serializedObject.ApplyModifiedProperties();\n            }\n            EditorGUI.EndProperty();\n        }\n    }\n#endif\n}<\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u501f\u5de5\u4f5c\u4e4b\u4fbf\u89e3\u6c7a\u4e86\u5148\u524d\u60f3\u4e0d\u5230\u7684 Drag and drop \u7684\u5224\u65b7. \u5229\u7528 Event.Current &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-2590","post","type-post","status-publish","format-standard","hentry","category-public"],"_links":{"self":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/posts\/2590","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/comments?post=2590"}],"version-history":[{"count":2,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/posts\/2590\/revisions"}],"predecessor-version":[{"id":2595,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/posts\/2590\/revisions\/2595"}],"wp:attachment":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/media?parent=2590"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/categories?post=2590"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/tags?post=2590"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}