博客迁移
个人博客站点,欢迎访问,www.jiingfengji.tech
本文介绍如何在PreferencesWindow中新增条目
在Unity编辑器拓展之六中,有介绍到部分PreferencesWindow.cs的代码,而本文从源码开始给大家介绍。
PreferencesWindow.cs中:
private void AddCustomSections()
{
Assembly[] loadedAssemblies = EditorAssemblies.loadedAssemblies;
for (int i = 0; i < loadedAssemblies.Length; i++)
{
Assembly assembly = loadedAssemblies[i];
Type[] typesFromAssembly = AssemblyHelper.GetTypesFromAssembly(assembly);
Type[] array = typesFromAssembly;
for (int j = 0; j < array.Length; j++)
{
Type type = array[j];
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
for (int k = 0; k < methods.Length; k++)
{
MethodInfo methodInfo = methods[k];
//关键在这一行
PreferenceItem preferenceItem = Attribute.GetCustomAttribute(methodInfo, typeof(PreferenceItem)) as PreferenceItem;
if (preferenceItem != null)
{
PreferencesWindow.OnGUIDelegate onGUIDelegate = Delegate.CreateDelegate(typeof(PreferencesWindow.OnGUIDelegate), methodInfo) as PreferencesWindow.OnGUIDelegate;
if (onGUIDelegate != null)
{
this.m_Sections.Add(new PreferencesWindow.Section(preferenceItem.name, onGUIDelegate));
}
}
}
}
}
}
代码片中标注的那一行,MSDN中的介绍是:
“检索应用于程序集、 模块、 类型成员或方法参数的指定类型的自定义属性。”
那么,上述代码中检索了程序中使用 PreferenceItem 的所有method,随后将带有PreferenceItem的methodInfo实例化成一个委托,进而构造一个Section对象,添加到m_Setions集合中。
接着,看Unity 文档,关于 PreferenceItem 的介绍。
https://docs.unity3d.com/2017.2/Documentation/ScriptReference/PreferenceItem.html
PreferenceItem属性允许您添加首选项到preferences窗口。
解释跟源码分析的一样,接下来进行代码测试。
[PreferenceItem("Preference Item")]
private static void SelfPreferenceItem()
{
EditorGUILayout.LabelField("Self Preference Item", EditorStyles.boldLabel);
if (GUILayout.Button("Button"))
{
Debug.LogError("Click");
}
EditorGUILayout.Space();
}
但是,发现有点不对劲,编辑器拓展之六中提到的选中左侧,出现问题了。没有自动选中新增的那一项。
然后通过断点,查看到反射出来的m_Sections集合里,并没有新增的那一项,使得在遍历的时候,没法自动选中它。
也就是说,AddCustomSections函数在此时并没有执行到,使得新增的 “Preference Item” 并没有被添加到m_Sections这个集合里。
查看一下源码中是合适调用的 AddCustomSections函数,
private void OnGUI()
{
if (this.m_RefreshCustomPreferences)
{
this.AddCustomSections();
this.m_RefreshCustomPreferences = false;
}
//节省篇幅,后面代码省略
}
也就是当m_RefreshCustomPreferences值为true时,执行一遍AddCustomSections函数。
完善代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System;
public class OpenPreferencesWindow : EditorWindow
{
[MenuItem("Tool/OpenPreferencesWindow")]
public static void Open()
{
OpenPreferencesWindow editor = EditorWindow.GetWindow<OpenPreferencesWindow>();
}
private void OnGUI()
{
if (GUILayout.Button("打开PerferencesWindow"))
{
Assembly assembly = Assembly.GetAssembly(typeof(UnityEditor.EditorWindow));
Type type = assembly.GetType("UnityEditor.PreferencesWindow");
type.GetMethod("ShowPreferencesWindow", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null);
EditorWindow window = EditorWindow.GetWindow(type);
//解决不能自动定位 新增条目 的问题
//手动调用一遍AddCustomSections函数
FieldInfo refreshField = type.GetField("m_RefreshCustomPreferences", BindingFlags.NonPublic | BindingFlags.Instance);
if ((bool)refreshField.GetValue(window))
{
type.GetMethod("AddCustomSections", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(window, null);
refreshField.SetValue(window, false);
}
FieldInfo sectionsField = type.GetField("m_Sections", BindingFlags.Instance | BindingFlags.NonPublic);
IList sections = sectionsField.GetValue(window) as IList;
Type sectionType = sectionsField.FieldType.GetGenericArguments()[0];
FieldInfo sectionContentField = sectionType.GetField("content", BindingFlags.Instance | BindingFlags.Public);
for (int i = 0; i < sections.Count; i++)
{
GUIContent sectionContent = sectionContentField.GetValue(sections[i]) as GUIContent;
if (sectionContent.text == "Preference Item")
{
FieldInfo sectionIndexField = type.GetField("m_SelectedSectionIndex", BindingFlags.Instance | BindingFlags.NonPublic);
sectionIndexField.SetValue(window, i);
return;
}
}
}
}
[PreferenceItem("Preference Item")]
private static void SelfPreferenceItem()
{
EditorGUILayout.LabelField("Self Preference Item", EditorStyles.boldLabel);
if (GUILayout.Button("Button"))
{
Debug.LogError("Click");
}
EditorGUILayout.Space();
}
}
完美收工!
以上知识分享,如有错误,欢迎指出,共同学习,共同进步。