对于Unity下例如按钮这种我们可以为它的监听事件手动进行赋值

如果需要通过编辑器扩展来动态为这些监听事件赋值应该如何去实现呢?

首先需要确认的是这些监听事件必须要符合一定的规则才能添加上:

1.必须是公共方法

2.不能带有返回值

大部分UI组件的参数只有一个,当然,你可以扩充UI组件增加更多参数。

我们主要使用的是UnityEventTools这个类中的方法。

监听事件的类型一共有以下几种模式:

 public enum PersistentListenerMode{/// <summary>///   <para>The listener will use the function binding specified by the even.</para>/// </summary>EventDefined,/// <summary>///   <para>The listener will bind to zero argument functions.</para>/// </summary>Void,/// <summary>///   <para>The listener will bind to one argument Object functions.</para>/// </summary>Object,/// <summary>///   <para>The listener will bind to one argument int functions.</para>/// </summary>Int,/// <summary>///   <para>The listener will bind to one argument float functions.</para>/// </summary>Float,/// <summary>///   <para>The listener will bind to one argument string functions.</para>/// </summary>String,/// <summary>///   <para>The listener will bind to one argument bool functions.</para>/// </summary>Bool,}

int、float、string、bool这些用法类似,例如我想为一个button添加一个GameObject.SetActive的方法监听:

        /// <summary>/// 为Button添加控制UnityEvent bool的方法/// </summary>/// <param name="button"></param>/// <param name="unityEvent"></param>public static void DynamicAddBoolUnityEvent(Button button,UnityAction<bool> unityEvent){UnityEventTools.AddBoolPersistentListener(button.onClick, unityEvent, true);}[MenuItem("Test/TestAddBool")]public static void DoAddBool(){Button btn = GameObject.Find("Button").GetComponent<Button>();DynamicAddUnityEventTools.DynamicAddBoolUnityEvent(btn, btn.gameObject.SetActive);}

如果想添加不带参数的方法则使用void模式:

        /// <summary>/// 为Button添加控制UnityEvent void的方法/// </summary>/// <param name="button"></param>/// <param name="unityEvent"></param>public static void DynamicAddVoidUnityEvent(Button button,UnityAction unityEvent){UnityEventTools.AddVoidPersistentListener(button.onClick, unityEvent);}[MenuItem("Test/TestAddVoid")]public static void DoAddVoid(){Button btn = GameObject.Find("Button").GetComponent<Button>();Test test = btn.GetComponent<Test>();DynamicAddUnityEventTools.DynamicAddVoidUnityEvent(btn, test.TestDebugVoid);}

如果想添加某个指定脚本上的指定方法作为监听响应的方法时,则使用Object模式:

        /// <summary>/// 为Button添加脚本中自定义的方法/// </summary>/// <param name="button"></param>/// <param name="callback"></param>/// <param name="argument"></param>public static void DynamicAddObjectUnityEvent<T>(Button button, UnityAction<T> callback, T argument) where T : Object{UnityEventTools.AddObjectPersistentListener(button.onClick,callback, argument);}[MenuItem("Test/TestAddObject1")]public static void DoAddObject1(){Button btn = GameObject.Find("Button").GetComponent<Button>();Test test = btn.GetComponent<Test>();DynamicAddUnityEventTools.DynamicAddObjectUnityEvent(btn, test.TestDebugAddObject1,btn.gameObject);}[MenuItem("Test/TestAddObject2")]public static void DoAddObject2(){Button btn = GameObject.Find("Button").GetComponent<Button>();Test test = btn.GetComponent<Test>();DynamicAddUnityEventTools.DynamicAddObjectUnityEvent(btn, test.TestDebugAddObject2, btn);}

这里有一个不太合理的地方就是它通过传入的argument参数作为类型的判断依据,所以导致无法在Editor下动态传入参数为None的形式,即它把参数的具体值和参数的类型放到了一个变量中去赋值。

 internal void RegisterObjectPersistentListener<T>(int index, UnityAction<T> call, T argument) where T : UnityEngine.Object{if (call == null)throw new ArgumentNullException(nameof (call), "Registering a Listener requires a non null call");if (!this.ValidateRegistration(call.Method, call.Target, PersistentListenerMode.Object, (UnityEngine.Object) argument == (UnityEngine.Object) null ? typeof (UnityEngine.Object) : argument.GetType()))return;this.m_PersistentCalls.RegisterObjectPersistentListener(index, call.Target as UnityEngine.Object, (UnityEngine.Object) argument, call.Method.Name);this.DirtyPersistentCalls();}
    public void RegisterObjectPersistentListener(int index,UnityEngine.Object targetObj,UnityEngine.Object argument,string methodName){PersistentCall listener = this.GetListener(index);listener.RegisterPersistentListener(targetObj, methodName);listener.mode = PersistentListenerMode.Object;listener.arguments.unityObjectArgument = argument;}
 public UnityEngine.Object unityObjectArgument{get{return this.m_ObjectArgument;}set{this.m_ObjectArgument = value;this.m_ObjectArgumentAssemblyTypeName = value != (UnityEngine.Object) null ? value.GetType().AssemblyQualifiedName : string.Empty;}}

在传入时通过这一行传递值 listener.arguments.unityObjectArgument = argument; 而在对应的set方法里面它的类型是通过获取它的value.GetType().AssemblyQualifiedName来得到的。

最后如果是自己扩展的UI组件它的响应事件带有多个参数,则使用EventDefine类型。

例如扩展的Button组件如下:

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class ButtonExtension : Button
{[Serializable]public class ButtonExtensionClickedEvent : UnityEvent<int,int> {}[SerializeField]private ButtonExtensionClickedEvent _onExtentionBtnClick = new ButtonExtensionClickedEvent();public class MyClass{public int Value;}[Serializable]public class ButtonExtensionClickedCustomEvent : UnityEvent<int,MyClass> {}[SerializeField]private ButtonExtensionClickedCustomEvent _onExtentionBtnCustomParamClick = new ButtonExtensionClickedCustomEvent();public ButtonExtensionClickedEvent OnExtentionBtnClick => _onExtentionBtnClick;public ButtonExtensionClickedCustomEvent OnExtentionBtnCustomParamClick => _onExtentionBtnCustomParamClick;public override void OnPointerClick(PointerEventData eventData){base.OnPointerClick(eventData);Debug.Log($"On Button PointerClick");OnExtentionBtnClick?.Invoke(1, 2);OnExtentionBtnCustomParamClick?.Invoke(1, new MyClass() {Value = 2});}
}

Editor绘制扩展脚本如下:

using UnityEditor;
using UnityEditor.UI;[CustomEditor(typeof(ButtonExtension), true)]
[CanEditMultipleObjects]
public class ButtonExtensionEditor : SelectableEditor
{SerializedProperty _onClickProperty;SerializedProperty _onExtentionBtnClick;SerializedProperty _onExtentionBtnCustomClick;protected override void OnEnable(){base.OnEnable();_onClickProperty = serializedObject.FindProperty("m_OnClick");_onExtentionBtnClick = serializedObject.FindProperty("_onExtentionBtnClick");_onExtentionBtnCustomClick = serializedObject.FindProperty("_onExtentionBtnCustomParamClick");}public override void OnInspectorGUI(){base.OnInspectorGUI();EditorGUILayout.Space();serializedObject.Update();EditorGUILayout.PropertyField(_onClickProperty);EditorGUILayout.PropertyField(_onExtentionBtnClick);EditorGUILayout.PropertyField(_onExtentionBtnCustomClick);serializedObject.ApplyModifiedProperties();}
}

为它添加监听时则使用:

        /// <summary>/// 为Button添加控制UnityEvent EventDefine的方法/// </summary>/// <param name="button"></param>/// <param name="unityEvent"></param>public static void DynamicAddEventDefineUnityEvent<T1, T2>(UnityEvent<T1, T2> button,UnityAction<T1, T2> unityEvent){UnityEventTools.AddPersistentListener(button, unityEvent);}        [MenuItem("Test/TestAddEventDefine")]public static void DoAddEventDefine(){ButtonExtension btnExt = GameObject.Find("ButtonExtension").GetComponent<ButtonExtension>();Button btn = GameObject.Find("Button").GetComponent<Button>();Test test = btn.GetComponent<Test>();DynamicAddUnityEventTools.DynamicAddEventDefineUnityEvent(btnExt.OnExtentionBtnClick, test.TestDebugEventDefine);}[MenuItem("Test/TestAddEventDefineCustom")]public static void DoAddEventDefineCustom(){ButtonExtension btnExt = GameObject.Find("ButtonExtension").GetComponent<ButtonExtension>();Button btn = GameObject.Find("Button").GetComponent<Button>();Test test = btn.GetComponent<Test>();DynamicAddUnityEventTools.DynamicAddEventDefineUnityEvent(btnExt.OnExtentionBtnCustomParamClick, test.TestDebugEventCustomDefine);}

如果有其他泛型参数可以自行添加即可。

最后Test脚本只是一些测试方法符合对应的规则即可:

using UnityEngine;
using UnityEngine.UI;public class Test : MonoBehaviour
{public void TestDebugAddObject1(GameObject gob){}public void TestDebugAddObject2(Button btn){}public void TestDebugVoid(){}public void TestDebugEventDefine(int a, int b){Debug.Log($"The Sum Is {a + b}");}public void TestDebugEventCustomDefine(int a, ButtonExtension.MyClass b){Debug.Log($"The Sum Is {a + b.Value}");}
}

完整工程示意截图如下:

Unity编辑器扩展——在Editor下动态添加监听事件相关推荐

  1. html中下拉列表监听事件,ExtJS 下拉框监听事件、日期选择器监听事件、实现动态给items添加删除数据...

    本文将为您描述ExtJS 下拉框监听事件.日期选择器监听事件.实现动态给items添加删除数据,具体实现方法: 1.下拉框 下拉框选择时,触发事件的方法: 在 Ext.form.ComboBox 组件 ...

  2. miniui单元格点击弹框_miniui 给表格行添加监听事件的几种方法以及点击某列列名数据不能排序的问题...

    最近在使用miniui框架做开发,在做表格行的点击监听事件中发现了几个属性,都可以起到监听效果但是执行的结果却大有不同.好了废话不多说,直接上代码. autoload="true" ...

  3. js原生给生成的html添加点击事件,原生js为动态元素添加监听事件

    //已存在div //创建标签 function createpage(){ var span=document.createElement('span') span.innerHTML=" ...

  4. js下拉列表添加监听事件(支持所有主流浏览器)

    1.需求效果预览 2.核心代码 <div class="select"><span>请选择学科:</span><select id = & ...

  5. js常用对象:点击、双击、onload事件、鼠标相关、onblur事件和onfocus事件等;通过循环给多个元素添加事件、通过addEventListener() 方法 监听事件函数...

    1.通过标签内部添加事件 (1)onclick事件:单击事件 (2)ondbclick事件:双击事件 (3)onload事件:只能在body中使用,入口函数里有:window.   .οnlοad=f ...

  6. Unity编辑器扩展之EditorWindow

    Unity编辑器扩展之EditorWindow 继承这个类的编辑器脚本可以用来创建一个编辑器窗口,类似Inspector窗口 若要在这个类中添加一些控件,可以使用GUI和GUILayout控件,还可以 ...

  7. Unity3D Editor 编辑器扩展3 Editor脚本

    Unity3D Editor 编辑器扩展3 Editor脚本 环境:Unity2017.2 语言:C# 总起: 在编辑Unity项目的时候,总不可能避免的接触到Unity自身自带的Inspector参 ...

  8. Unity编辑器扩展: 程序化打图集工具

    开始前的声明:该案例中图集所使用图片资源均来源于网络,仅限于学习使用 一.前言 关于编辑器扩展相关的知识,在前面的两篇内容中做了详细的描述,链接地址: 第一篇 :Unity编辑器扩展 UI控件篇 第二 ...

  9. 【Unity编辑器扩展】(三)PSD转UGUI Prefab, 一键拼UI解放美术/程序(完结)

    工具效果: 第一步,把psd图层转换为可编辑的节点树,并自动解析UI类型.自动绑定UI子元素: 第二步, 点击"生成UIForm"按钮生成UI预制体 (若有UI类型遗漏可在下拉菜单 ...

最新文章

  1. 微软正式发布Azure Functions 2.0
  2. oracle数据库如何写翻页_oracle数据库如何写翻页
  3. CS231n(1):图片分类笔记与KNN编程作业
  4. 操作系统文件分配策略_操作系统中的文件分配方法
  5. java分隔符 字符串_用Java构建带分隔符的字符串的最佳方法是什么?
  6. 【Java TCP/IP Socket】 — close()/shutdownOutput()/shutdownInput() 分析
  7. MFC - CStdioFile 读取txt文件UNICODE 中文异常
  8. 毕业季怎么做答辩PPT?
  9. CDH6.3.2安装文档
  10. python绘制复杂表格_Matplotlib绘制表格
  11. 二年级课程表(4月18日-4月22日)
  12. 码市coding不能下载
  13. win7 安装openssh_win7系统安装OpenSSH的操作方法
  14. 讯飞语音包实现Android语音识别
  15. linux 命令行别名,bash命令行实用的别名-alias命令
  16. 【数字经济】概念、技术、实践:中国 500强泰康集团背后的数据驱动
  17. python--破解滑动验证码
  18. 三、简单刷题APP(题库是Excel)之在APP添加题目
  19. CentOS 163镜像使用帮助
  20. seo是什么|怎么做好seo|seo视频教程

热门文章

  1. 伽马函数公式 ∫x^ne^{-x}dx=n!
  2. Ubuntu,CentOS安装TIM(QQ),liunx通用
  3. 模块化 AMD与CMD 规范
  4. Gartner云端盘点,浅谈2017IaaS魔力象限
  5. Practical_RichFaces要点Chapter11
  6. 04 分布式文件系统以及MapReduce入门程序
  7. SPSS显著性差异分析及字母标记
  8. SSH免密失败并报错:no mutual signature algorithm
  9. 使用QImage生成纯透明png图片
  10. uniApp APP端调起微信支付失败errCode:-100的踩坑