Unity UI Button 事件优先级调整技术方案

Unity UI Button 事件优先级调整技术方案

在 Unity 项目开发过程中,针对 UI Button 的事件执行顺序控制是一个常见需求。本文详细阐述两种将新添加事件置于第一个执行位置的方法,旨在为开发者提供全面且专业的技术参考。

一、基于反射机制的事件插入方法

(一)核心函数:InsertClickListenerAtStart

以下函数实现了将指定的 UnityAction 插入到 ButtononClick 事件列表头部,确保其在其他已有事件之前执行。

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

此方法通过反射深入到 UnityEventBaseButton 的内部实现机制,精准地操作事件调用列表。其核心步骤包括:

  • 首先,对目标事件进行去重操作,避免同一事件多次添加导致的逻辑混乱。
  • 接着,利用反射获取 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 变量。同时,将 ButtononClick 事件替换为一个新的空事件,以便后续插入自定义事件。
  • 当用户点击按钮时,OnPointerClick 方法被触发。首先,执行自定义的 BeforeOnClick 事件,这是我们希望优先执行的事件。
  • 接着,将 ButtononClick 事件恢复为原始备份的事件,并立即触发该事件,从而保证了自定义事件在原始事件之前执行。
  • 最后,销毁 OneTimeButtonEventInsertor 脚本实例,避免对后续事件处理产生不必要的干扰。

综上所述,这两种方法分别从底层反射和高层脚本代理的角度,为 Unity UI Button 事件优先级控制提供了有效的解决方案。开发者可根据项目的具体需求、性能要求以及代码维护性等因素,灵活选择合适的方法来实现按钮事件的精准排序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CTFHUB 信息泄露 备份文件下载-网站源码

根据提示应是猜测网站源码的备份文件&#xff0c;可以采用bp拼接文件名和后缀 开启bp抓包后设置第一个攻击点导入文件名 第二个攻击点导入后缀 开始暴力破解&#xff0c;有成功响应的 拼接到网站后缀后可以直接下载 解压缩后记事本的名字就是flag 总结&#xff1a; …

Latex 转换为 Word(使用GrindEQ )(英文转中文,毕业论文)

效果预览 第一步&#xff1a; 告诉chatgpt&#xff1a; 将latex格式中的英文翻译为中文&#xff08;符号和公式不要动&#xff09;,给出latex格式第二步&#xff1a; Latex 转换为 Word&#xff08;使用GrindEQ &#xff09; 视频 https://www.bilibili.com/video/BV1f242…

X射线衍射全岩分析在岩石学研究中的重要性

X射线衍射全岩分析在岩石学研究中的重要性 X射线衍射&#xff08;XRD&#xff09;全岩分析在岩石学研究中扮演着至关重要的角色&#xff0c;它是一种非破坏性的分析技术&#xff0c;能够提供岩石和矿物的精细结构信息。通过解析材料内部原子排列的特征&#xff0c;XRD不仅揭示了…

12.12 深度学习-卷积的注意力机制-通道注意力SENet

# 告诉模型训练的时候 对某个东西 给予额外的注意 额外的权重参数 分配注意力 # 不重要的就抑制 降低权重参数 比如有些项目颜色重要 有些是形状重要 # 通道注意力 一般都要比较多的通道加注意力 # SENet # 把上层的特征图 自动卷积为 1X1的通道数不变的特征图 然后给每一个…

使用 Python 从 ROS Bag 中提取图像:详解与实现

在机器人应用中&#xff0c;ROS (Robot Operating System) 是一个常见的框架。ROS Bag&#xff08;rosbag&#xff09;是 ROS 中用于记录和回放数据流&#xff08;例如传感器数据、话题消息等&#xff09;的一种强大工具。有时&#xff0c;我们需要将存储在 rosbag 文件中的图像…

【Bolt.new + PromptCoder】三分钟还原油管主页

【Bolt.new PromptCoder】三分钟还原油管主页 PromptCoder官网&#xff1a;PromptCoder Bolt官网&#xff1a;https://bolt.new/ Bolt 是什么&#xff1f; Bolt.new 是一个提供创建全栈网络应用服务的平台。它允许用户通过提示&#xff08;Prompt&#xff09;、运行&#x…

【小白你好】深度学习的认识和应用:CNN、GNN、LSTM、Transformer、GAN与DRL的对比分析

大家好&#xff01;今天我们来聊聊一个热门话题——深度学习。别担心&#xff0c;我会用简单易懂的语言&#xff0c;让每个人都能理解。我们将一起探索什么是深度学习&#xff0c;它有哪些类似的概念&#xff0c;以及其中几种主要的算法&#xff1a;卷积神经网络&#xff08;CN…

定时/延时任务-万字解析Spring定时任务原理

文章目录 1. 概要2. EnableScheduling 注解3. Scheduled 注解4. postProcessAfterInitialization 解析4.1 createRunnable 5. 任务 Task 和子类6. ScheduledTaskRegistrar6.1 添加任务的逻辑6.2 调度器初始化6.3 调用时机 7. taskScheduler 类型7.1 ConcurrentTaskScheduler7.2…

JumpServer开源堡垒机搭建及使用

目录 一,产品介绍 二,功能介绍 三,系统架构 3.1 应用架构 3.2 组件说明 3.3 逻辑架构 3.3 逻辑架构 四,linux单机部署及方式选择 4.1 操作系统要求(JumpServer-v3系列版本) 4.1.1 数据库 4.1.3创建数据库参考 4.2 在线安装 4.2.1 环境访问 4.3 基于docker容…

单目动态新视角合成

目录 单目动态新视角合成 Generative Camera Dolly:Extreme Monocular Dynamic Novel View Synthesis 单目动态新视角合成 Generative Camera Dolly: Extreme Monocular Dynamic Novel View Synthesis Generative Camera Dolly: Extreme Monocular Dynamic Novel View Synth…

ResNet网络:深度学习中的革命性架构

目录 ​编辑 引言 ResNet网络的特点 1. 残差块&#xff08;Residual Block&#xff09; 2. 恒等映射&#xff08;Identity Mapping&#xff09; 3. 深层网络训练 4. Batch Normalization 5. 全局平均池化 6. 灵活的结构 ResNet的应用案例 ResNet的研究进展 实战案例…

如何在Playwright中操作窗口的变化

Playwright 是一个用于自动化 Web 应用测试的现代工具支持多种语言&#xff08;包括 Java&#xff09;及多个浏览器。它提供了一致的 API 来控制浏览器行为&#xff0c;其中包括窗口操作&#xff0c;如最大化。本文将详细介绍如何在 Java Playwright 中实现浏览器窗口的最大化 …

【GoF23种设计模式】02_单例模式(Singleton Pattern)

文章目录 前言一、什么是单例模式&#xff1f;二、为什么要用单例模式&#xff1f;三、如何实现单例模式&#xff1f;总结 前言 提示&#xff1a;设计者模式有利于提高开发者的编程效率和代码质量&#xff1a; GoF&#xff08;Gang of Four&#xff0c;四人帮&#xff09;设计…

Node.js day-01

01.Node.js 讲解 什么是 Node.js&#xff0c;有什么用&#xff0c;为何能独立执行 JS 代码&#xff0c;演示安装和执行 JS 文件内代码 Node.js 是一个独立的 JavaScript 运行环境&#xff0c;能独立执行 JS 代码&#xff0c;因为这个特点&#xff0c;它可以用来编写服务器后端…

又要考试了

一、实现无名管道练习&#xff1a;父进程写入管道&#xff0c;子进程读取管道数据。 #include<myhead.h> int main(int argc, const char *argv[]) {int fd[2];char buff[1024]"王吕阳&#xff0c;崔庆权别卷了";char s[1024];if(pipe(fd)-1){perror("pi…

LoadBalancer负载均衡和Nginx负载均衡区别理解

LoadBalancer和Nginx都是用来做负载均衡用的&#xff0c;那二者有什么区别呢&#xff1f; Nginx服务器端的负载均衡&#xff1a; 所有请求都先发到nginx&#xff0c;然后再有nginx转发从而实现负载均衡。LoadBalancer是本地的负载均衡&#xff1a; 它是本地先在调用微服务接口…

Linux shell脚本练习(六)

清除系统默认文件缓存/tmp中超过30天未访问的文件 #!/bin/bash# 临时文件存放的目录 TEMP_DIR"/tmp" # 设置保留文件的天数 RETENTION_DAYS30# 判断临时目录是否存在 if [ ! -d "$TEMP_DIR" ]; thenecho "临时目录 $TEMP_DIR 不存在&#xff01;&quo…

【MQTT 编程】-API

文章目录 1 MQTTClient_message 结构体2 创建客户端对象3 连接服务端3 设置回调函数4 发布消息5 订阅主题和取消订阅主题5.1 订阅主题5.2 取消订阅 6 断开服务连接 1 MQTTClient_message 结构体 很重要的结构体&#xff0c;客户端应用程序发布消息和接收消息都是围绕这这个结构…

Technitium DNS Server的基本使用1(创建主区域,A记录,开启递归查询,递归到114.114.114.114)

Technitium DNS Server Technitium DNS Server搭建 搭建请看博主的上篇博客&#xff0c;内外网的方法都有 链接: 内网搭建Technitium DNS Server详细教程 登陆进去是以下界面 这个界面主要是监控&#xff0c;有访问的时候就会有波动 创建主区域&#xff0c;A记录 写上主区…

OpenAI 与 ChatGPT 的关系解析

OpenAI 与 ChatGPT 的关系解析 基本关系 OpenAI 是公司&#xff0c;ChatGPT 是产品 OpenAI 是一家人工智能研究公司ChatGPT 是 OpenAI 开发的一款 AI 聊天产品ChatGPT 使用的是 OpenAI 开发的 GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型 OpenAI 的…