Unity编辑器拓展之七:如何在PreferencesWindow中新增条目

博客迁移

个人博客站点,欢迎访问,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中的介绍是:
“检索应用于程序集、 模块、 类型成员或方法参数的指定类型的自定义属性。”

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();
    }
}

完美收工!

以上知识分享,如有错误,欢迎指出,共同学习,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值