Unity UI Button 事件优先级调整技术方案
Unity UI Button 事件优先级调整技术方案
在 Unity 项目开发过程中,针对 UI Button 的事件执行顺序控制是一个常见需求。本文详细阐述两种将新添加事件置于第一个执行位置的方法,旨在为开发者提供全面且专业的技术参考。
一、基于反射机制的事件插入方法
(一)核心函数:InsertClickListenerAtStart
以下函数实现了将指定的 UnityAction 插入到 Button 的 onClick 事件列表头部,确保其在其他已有事件之前执行。
private void InsertClickListenerAtStart(Button button, UnityAction action)
{// 1. 事件去重处理var onClick = button.onClick;onClick.RemoveListener(action); // 确保不会重复添加// 2. 反射获取 m_Calls 字段var field = typeof(UnityEventBase).GetField("m_Calls", BindingFlags.NonPublic | BindingFlags.Instance);if (field!= null){var invokableCallList = field.GetValue(onClick);if (invokableCallList!= null){// 3. 获取 m_RuntimeCalls 字段var runtimeCallsField = invokableCallList.GetType().GetField("m_RuntimeCalls", BindingFlags.NonPublic | BindingFlags.Instance);if (runtimeCallsField!= null){// 4. 创建新的 InvokableCallvar invokableCallType = typeof(UnityEvent).Assembly.GetType("UnityEngine.Events.InvokableCall");if (invokableCallType!= null){var constructor = invokableCallType.GetConstructor(new[] { typeof(UnityAction) });if (constructor!= null){var newCall = constructor.Invoke(new object[] { action });// 5. 获取 Insert 方法并插入新事件var runtimeCalls = runtimeCallsField.GetValue(invokableCallList);var insertMethod = runtimeCalls.GetType().GetMethod("Insert");if (insertMethod!= null){insertMethod.Invoke(runtimeCalls, new object[] { 0, newCall });// 6. 设置 m_NeedsUpdate 为 truevar needsUpdateField = invokableCallList.GetType().GetField("m_NeedsUpdate", BindingFlags.NonPublic | BindingFlags.Instance);if (needsUpdateField!= null){needsUpdateField.SetValue(invokableCallList, true);}}}}}}}
}
此方法通过反射深入到 UnityEventBase 和 Button 的内部实现机制,精准地操作事件调用列表。其核心步骤包括:
- 首先,对目标事件进行去重操作,避免同一事件多次添加导致的逻辑混乱。
- 接着,利用反射获取
m_Calls字段,该字段存储了事件的可调用列表信息。在确保获取成功后,进一步获取m_RuntimeCalls字段,这是实际存储运行时事件调用信息的关键结构。 - 随后,根据
UnityEvent程序集动态获取InvokableCall类型,并创建一个新的实例,该实例包装了我们要插入的action。 - 最后,获取
m_RuntimeCalls列表的Insert方法,将新创建的InvokableCall实例插入到列表头部(索引为 0),并设置m_NeedsUpdate标志为true,以确保事件系统在后续处理中能够正确更新状态。
二、基于脚本代理的事件暂存与插入方法
(一)核心脚本:OneTimeButtonEventInsertor
通过创建 OneTimeButtonEventInsertor 脚本,实现了一种更为直观的事件顺序控制方式。
public class OneTimeButtonEventInsertor : MonoBehaviour, IPointerClickHandler
{private Button button;// 自定义事件,用于在 EventTrigger 之前调用public UnityEvent BeforeOnClick = new UnityEvent();public Button.ButtonClickedEvent OnClick;private void Awake(){button = GetComponent<Button>();OnClick = button.onClick;button.onClick = new Button.ButtonClickedEvent();}public void OnPointerClick(PointerEventData eventData){// 先执行 BeforeOnClick 事件BeforeOnClick?.Invoke();button.onClick = OnClick;button.onClick.Invoke();Destroy(this);}
}
该脚本的工作原理如下:
- 在
Awake方法中,获取目标Button组件,并备份其原始的onClick事件到OnClick变量。同时,将Button的onClick事件替换为一个新的空事件,以便后续插入自定义事件。 - 当用户点击按钮时,
OnPointerClick方法被触发。首先,执行自定义的BeforeOnClick事件,这是我们希望优先执行的事件。 - 接着,将
Button的onClick事件恢复为原始备份的事件,并立即触发该事件,从而保证了自定义事件在原始事件之前执行。 - 最后,销毁
OneTimeButtonEventInsertor脚本实例,避免对后续事件处理产生不必要的干扰。
综上所述,这两种方法分别从底层反射和高层脚本代理的角度,为 Unity UI Button 事件优先级控制提供了有效的解决方案。开发者可根据项目的具体需求、性能要求以及代码维护性等因素,灵活选择合适的方法来实现按钮事件的精准排序。
相关文章:
Unity UI Button 事件优先级调整技术方案
Unity UI Button 事件优先级调整技术方案 在 Unity 项目开发过程中,针对 UI Button 的事件执行顺序控制是一个常见需求。本文详细阐述两种将新添加事件置于第一个执行位置的方法,旨在为开发者提供全面且专业的技术参考。 一、基于反射机制的事件插入方…...
算法训练营day1 | 704二分查找,27移除元素, 34, 35
已经找到工作,但希望再试试春招,距离春招还剩两个月,加油。 这两道题都刷过很多遍了,没什么好说的直接过。 704 本以为刷了很多次没想到还是做错了,有些小细节要注意。 这里是迭代式的,函数式的也不难。 …...
66 基于单片机的太阳能充电、温度检测、档位PWM调速系统
所有仿真详情导航: PROTEUS专栏说明-CSDN博客 目录 一、主要功能 二、硬件资源 三、主程序编程 四、资源下载 一、主要功能 基于52单片机,采用DS18B20温度传感器检测温度,采用滑动变阻器连接ADC0832数模转换器模拟电量,采用…...
RK3576 Android14,内存大于4G时UVC应用无法申请内存
最近有个项目需要将Linux虚拟成UVC摄像头,开发过程中遇到一个奇怪的事情,通过V4l2框架接口申请内存时,相同的板子,只是内存一个4G一个8G。4G的内存可以申请成功,8G就不行。提示“内存不足” 内存更大反而内存不足&…...
12.12 深度学习-卷积的注意力机制-通道注意力SENet
# 告诉模型训练的时候 对某个东西 给予额外的注意 额外的权重参数 分配注意力 # 不重要的就抑制 降低权重参数 比如有些项目颜色重要 有些是形状重要 # 通道注意力 一般都要比较多的通道加注意力 # SENet # 把上层的特征图 自动卷积为 1X1的通道数不变的特征图 然后给每一个…...
H5 scss 移动端的样式适配
在移动端样式的scss文件中,出现了这些变量 env() 与 constant() 设置安全区域,是css里IOS11新增的属性,webkit的css函数,用于设定安全区域与边界的距离,有4个预定义变量: safe-area-inset-left: 安全区域距…...
【JAVA】Java项目实战—移动端项目:天气查询APP
在移动互联网时代,天气查询应用程序(APP)是日常生活中不可或缺的一部分。无论是出门旅行、上班通勤,还是安排户外活动,获取实时天气信息都至关重要。Java作为一种强大且广泛使用的编程语言,特别适合用于开发…...
SpringBoot - 动态端口切换黑魔法
文章目录 关键技术点核心原理Code 关键技术点 利用 Spring Boot 内嵌 Servlet 容器 和 动态端口切换 的方式实现平滑更新的方案,关键技术点如下: Servlet 容器重新绑定端口:Spring Boot 使用 ServletWebServerFactory 动态设置新端口。零停…...
Java爬虫技术:挖掘淘宝数据的利器
在当今大数据时代,网络爬虫技术已经成为获取网络数据的重要手段。Java作为一种强大且灵活的编程语言,非常适合开发复杂的网络爬虫系统。本文将详细介绍Java爬虫能够爬取的淘宝数据类型,并提供具体的代码示例,帮助您快速入门并掌握…...
Chromium for Android 浏览器的编译和安装
Chromium for Android 浏览器的编译和安装 Chromium for Android 浏览器的编译和安装环境要求和配置Chromium for Android源码下载安装 depot_tools获取代码转换现有的Linux检出安装额外的构建依赖运行钩子 Chromium for Android源码编译设置编译环境 编译 ChromiumChromium fo…...
实景视频与模型叠加融合?
[视频GIS系列]无人机视频与与实景模型进行实时融合_无人机视频融合-CSDN博客文章浏览阅读1.5k次,点赞28次,收藏14次。将无人机视频与实景模型进行实时融合是一个涉及多个技术领域的复杂过程,主要包括无人机视频采集、实景模型构建、视频与模型…...
Scala的隐式类
package hfd //隐式类 //任务:给之前的BaseUser添加新的功能,但是不要直接去改代码 //思路:把BaseUser通过隐式转换,改成一个新类型,而这个新类型中有这新的方法 //implicit class一个隐式转换函数类 //作用࿱…...
常见软件设计模式介绍:三层架构、MVC、SSM、EDD、DDD
三层架构(View Service Dao) 三层架构是指:视图层 view(表现层),服务层 service(业务逻辑层),持久层 Dao(数据访问层) 表现层:直接跟前…...
Springboot技术栈常见问题及搭建步骤
一. SpringBoot介绍 1.1. 引言 为了使用SSM框架去开发, 准备SSM框架的模板配置 为了使Spring整合第三方框架, 单独的去编写xml文件 导致SSM项目后期xml文件特别多, 维护xml文件的成本是很高的 SSM工程部署也是很麻烦, 依赖第三方的容器 SSM开发方式很是笨重 1.2 SpringBoot …...
session 共享服务器
1.安装 kryo-3.0.3.jar asm-5.2.jar objenesis-2.6.jar reflectasm-1.11.9.jar minlog-1.3.1.jar kryo-serializers-0.45.jar msm-kryo-serializer-2.3.2.jar memcached-session-manager-tc9-2.3.2.jar spymemcached-2.12.3.jar memcached-session-manager-2.3.2.jar …...
vue2:v-for实现的el-radio-group选中时显示角标,并自定义选中按钮的字体颜色和背景色
项目中需要实现一组预定义查询,每一个查询按钮在选中时右上角显示一个角标,展示当前查询返回的数据条目。 1、text-color="#3785FF" fill="#E6EAF1" 处理选中时的字体颜色和背景色,如上图,分别为蓝色和浅灰色。 2、badge中:value="selectedRadio…...
【Linux】-学习笔记10
第八章、Linux下的火墙管理及优化 1.什么是防火墙 从功能角度来讲 防火墙是位于内部网和外部网之间的屏障,它按照系统管理员预先定义好的规则来控制数据包的进出 从功能实现角度来讲 火墙是系统内核上的一个模块netfilter(数据包过滤机制) …...
鸿蒙NEXT开发案例:九宫格随机
【引言】 在鸿蒙NEXT开发中,九宫格抽奖是一个常见且有趣的应用场景。通过九宫格抽奖,用户可以随机获得不同奖品,增加互动性和趣味性。本文将介绍如何使用鸿蒙开发框架实现九宫格抽奖功能,并通过代码解析展示实现细节。 【环境准…...
深度解析:RTC电路上的32.768KHz时钟的频偏及测试
1、什么是RTC RTC是Real-Time Clock(实时时钟)的缩写,通常在电子产品中,是用时钟电路(外部采用时钟芯片,比如AiP8563)或时钟模块(SOC内部包含了时钟模块,只需要外接32.768KHz晶振)来…...
Scala的泛型
需求:定义一个名为getMiddleEle 的方法用它来获取当前的列表的中间位置的值中间位置的下标 长度/2目标:getMiddleEle(List(1,2,3,4,5)) > 5/2 2 > 下标为2的元素是:3 getMiddleEle(List(1,2,3,4)) > 4/2 2 > 下标为2的元素是:3格式如下: 定义一个函数的格式:def…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
