当前位置: 首页 > news >正文

「OC」剪不断,理还乱——UIResponder、UIGestureRecognizer、UIControl的响应优先级探究

「OC」剪不断,理还乱——UIResponder、UIGestureRecognizer、UIControl的响应优先级探究

文章目录

  • 「OC」剪不断,理还乱——UIResponder、UIGestureRecognizer、UIControl的响应优先级探究
    • 前言
    • 介绍
      • UIResponder
      • UIGestureRecognizer
      • UIControl
    • 正文
      • UIGestureRecognizer和UIResponder
        • 短按
        • 快速按下
        • 长按
        • 补充
    • 乱上加乱
      • 在view上添加点击手势识别器
      • 在button上添加手势识别器
    • 总结
    • 参考资料

前言

上一篇我们记录了编译器是如何找到最佳响应者以及响应者链的构成「OC」初识iOS事件处理流程,那么今天我们就来探究,UIResponder、UIGestureRecognizer、UIControl在处理事件时的优先级,以及相关的细节。让我们开始UIResponder、UIGestureRecognizer、UIControl的爱恨情仇吧

介绍

先简单介绍一下本文的三个主角

UIResponder

UIResponder是iOS中处理事件的核心类,它是许多重要UI类的父类,包括UIApplication、UIView和UIViewController。

主要特点:

  • 定义了响应和处理事件的接口
  • 是构建响应者链的基础
  • 可以处理触摸事件、运动事件、远程控制事件等

UIGestureRecognizer

UIGestureRecognizer是一个抽象基类,用于检测特定的触摸手势。

主要特点:

  • 简化了复杂手势的识别过程
  • 可以添加到任何UIView上
  • 有多个具体子类,如UIPanGestureRecognizer, UITapGestureRecognizer等

补充:其实手势接受事件也是通过与其他两者类似的方式,即触摸开始——触摸移动——触摸取消——触摸结束,他们被写在了UIGestureRecognizerSubclass.h之中,我们下文探究触摸优先级时,打印日志需要在UITapGestureRecognizer的子类之中引入 import <UIKit/UIGestureRecognizerSubclass.h>

手势分为离散型手势(discrete gestures)和持续型手势(continuous gesture)。系统提供的离散型手势包括点按手势(UITapGestureRecognizer)和轻扫手势(UISwipeGestureRecognizer),其余均为持续型手势。

在手势之中,有三个属性比较重要

@property(nonatomic) BOOL cancelsTouchesInView;
@property(nonatomic) BOOL delaysTouchesBegan;
@property(nonatomic) BOOL delaysTouchesEnded;

cancelsTouchesInView:默认值为YES,表示当手势识别器成功识别了手势之后,会通知Application取消响应链对事件的响应,并不再传递事件给hit-test view。若设置成NO,表示手势识别成功后不取消响应链对事件的响应,事件依旧会传递给hit-test view。

delaysTouchesBegan:默认为NO。默认情况下手势识别器在识别手势期间,当触摸状态发生改变时,Application都会将事件传递给手势识别器和hit-tested view;若设置成YES,则表示手势识别器在识别手势期间,截断事件,即不会将事件发送给hit-tested view。

delaysTouchesEnded:默认为YES。当手势识别失败时,若此时触摸已经结束,会延迟一小段时间(0.15s)再调用响应者的 touchesEnded:withEvent:;若设置成NO,则在手势识别失败时会立即通知Application发送状态为end的touch事件给hit-tested view以调用 touchesEnded:withEvent: 结束事件响应。

UIControl

UIControl是一个抽象基类,为特定的用户界面元素(如按钮、开关、滑块等)提供了基础结构。它的继承了UIView,而UIView又继承于UIResponder,所以在某些时候我们可以将两者等同看待,在细节方面有相似之处

主要特点:

  • 继承自UIView
  • 定义了一组标准的控制事件(如触摸按下、抬起、拖动等)
  • 允许为不同事件添加多个目标动作

target-action

  • target:处理交互事件的对象
  • action:处理交互事件的方式

UIControl作为能够响应事件的控件,必然也需要待事件交互符合条件时才去响应,因此也会跟踪事件发生的过程。不同于UIResponder以及UIGestureRecognizer通过 touches 系列方法跟踪,UIControl有其独特的跟踪方法:

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)cancelTrackingWithEvent:(nullable UIEvent *)event;

大致方法其实与我们先前接触的UIResponder的那4个方法相同,毕竟UIControl本身也是UIResponder的子类,但是这个UIControl之中的tracking系列的方法是在touch系列之中进行实现的。

具体的target-action具体流程,我按着网上给出的内容叙述一遍:

UIControl控件通过 addTarget:action:forControlEvents: 添加事件处理的target和action,当事件发生时,会调用 sendAction:to:forEvent: 将target、action以及event对象发送给全局应用,Application对象再通过 sendAction:to:from:forEvent: 向target发送action。

img

另外,若不指定target,即 addTarget:action:forControlEvents: 时target传空,那么当事件发生时,Application会在响应链上从上往下寻找能响应action的对象。

正文

接下来我们来探究一下,事件产生的先后优先顺序

我们先写一个简单的demo进行测试

#import "ViewController.h"@interface ViewController () <UITableViewDelegate, UITableViewDataSource>@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSArray *dataSource;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.title = @"手势冲突测试";self.view.backgroundColor = [UIColor whiteColor];// 初始化数据源self.dataSource = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8"];// 创建并设置UITableViewself.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];self.tableView.delegate = self;self.tableView.dataSource = self;self.tableView.backgroundColor = [UIColor orangeColor];self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;[self.view addSubview:self.tableView];UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(actionTapView)];[self.view addGestureRecognizer:tap];UIButton *bottomButton = [UIButton buttonWithType:UIButtonTypeCustom];[bottomButton setTitle:@"点我无压力" forState:UIControlStateNormal];[bottomButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];bottomButton.backgroundColor = [UIColor cyanColor];bottomButton.frame = CGRectMake(20, CGRectGetMaxY(self.view.bounds) - 60, CGRectGetWidth(self.view.bounds) - 40, 40);[bottomButton addTarget:self action:@selector(buttonTap) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:bottomButton];
}-(void)buttonTap {NSLog(@"button clicked!");
}#pragma mark - UITableViewDataSource- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {return self.dataSource.count;
}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {return 55;
}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {static NSString *cellIdentifier = @"Cell";UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];if (!cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];cell.backgroundColor = [UIColor orangeColor];cell.textLabel.textColor = [UIColor whiteColor];}cell.textLabel.text = self.dataSource[indexPath.row];return cell;
}#pragma mark - UITableViewDelegate- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {NSLog(@"cell selected!");
}- (void)actionTapView{NSLog(@"backview taped");
}@end

我们进行点击进行尝试

Sep-03-2024 21-21-52

可以发现当我短按cell的时候,触发的是手势事件,只有长按cell才能够触发点击cell的方法,这到底是为什么啊?

由于这三兄弟,都实现了类似的方法,所以我在他们的子类之中,增加的打印日志的行为,以探究这三者的运行关系

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;

具体打印日志的方式如下

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"%s",__func__);[super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"%s",__func__);[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"%s",__func__);[super touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"%s",__func__);[super touchesCancelled:touches withEvent:event];
}

UIGestureRecognizer和UIResponder

关于UIGestureRecognizer和UIResponder的问题,其实上面UIGestureRecognizer的属性已经给我们透露一些相关的内容了,那我们就先从我们最有疑问的开始探究吧。

短按

image-20240904155530051

在短按的时候我们可以看到,其实在我们短按的时候,手势识别先开始,而tableView的触摸在随后也开始了,之所以我们的无法触发选择cell的方法是因为,cell的触摸在手势触发之后被Application给取消了。

引用官方文档的翻译:Window在将事件传递给hit-tested view之前,会先将事件传递给相关的手势识别器并由手势识别器优先识别。若手势识别器成功识别了事件,就会取消hit-tested view对事件的响应;若手势识别器没能识别事件,hit-tested view才完全接手事件的响应权。

因此通过这个点,我们可以总结出:手势识别器比UIResponder具有更高的事件响应优先级!!

快速按下

有的读者可能就有疑惑了,咋一听,如果短按的道理是上面解释的那样,那么按理来说快速按下的响应过程和短按应该是相同的才对。

我们知道UITableView是UIScrollView的子类,而UIScrollView因为要滚动,所以对事件做了特殊的处理: 当UIScrollView接收到事件之后,会暂时劫持当前的事件,会产生一个UIScrollViewDelayedTouchesBeganGestureRecognizer的手势识别器识别是否进行滚动操作,由于手势操作在应用之中可以进行同时识别,所以当UIScrollView这个机制劫持了触摸事件,和TableViewtouchesBegan: 的调用时间相差大概为0.15s,由于UIScrollViewDelayedTouchesBeganGestureRecognizer拦截了touchesBegan: 发送,当我们点击时间过短的话,没过延迟时间触摸就结束了,因此就会出现以下情况。

请添加图片描述

长按

由于我们手势劫持判断是有时效的,当时效结束之后,hit-tested view才完全接手事件,停止向手势识别器发送事件,仅向hit-test view发送事件。

image-20240904155620433

补充

刚刚我们讲的是离散型的手势,接下来我们补充一下持续性手势,仍是相同的内容但是把手势改为持续性的手势,

image-20240904200533662

我们可以看到即便滑动手势识别器识别了手势,Application也会依旧发送事件给tableView。

另外,在滑动的过程中,若手势识别器未能识别手势,则事件在触摸滑动过程中会一直传递给hit-tested view,直到触摸结束。

乱上加乱

如果让本就纠缠不清,复杂无比的UIGestureRecognizer和UIResponder,再有第三者UIControl插足呢?

真是头大,看的我都快看不懂字了。

根据官方文档,总结内容如下:UIControl会阻止父视图上的手势识别器行为,也就是UIControl处理事件的优先级比UIGestureRecognizer高,但前提是相比于父视图上的手势识别器。

我们设置一下情景

请添加图片描述

在view上添加点击手势识别器

image-20240904210011938

点击button后,事件先传递给手势识别器,再传递给作为hit-tested view存在的button(UIControl本身也是UIResponder),由于button阻止了父视图BlueView中的手势识别器的识别,导致手势识别器识别失败,button完全接手了事件的响应权,事件最终由button响应;

在button上添加手势识别器

请添加图片描述

点击button后,事件先传递给手势识别器,再传递给作为hit-tested view存在的button(UIControl本身也是UIResponder),button未阻止其本身绑定的手势识别器的识别,因此手势识别器先识别手势并识别成功,而后通知Application取消响应链对事件的响应,因为 touchesCancelled 被调用,同时 cancelTrackingWithEvent 跟着调用,因此button的target-action得不到执行。

所以我们可以得出结论:

UIControl比其父视图上的手势识别器具有更高的事件响应优先级。

总结

最后我们可以笼统的得出一个结论:UIRespnder、UIGestureRecognizer、UIControl,笼统地讲,事件响应优先级依次递增。

参考资料

01 触摸事件传递

iOS事件处理

iOS——事件、响应链和传递链

iOS触摸事件全家桶

UIGestureRecognizer

相关文章:

「OC」剪不断,理还乱——UIResponder、UIGestureRecognizer、UIControl的响应优先级探究

「OC」剪不断&#xff0c;理还乱——UIResponder、UIGestureRecognizer、UIControl的响应优先级探究 文章目录 「OC」剪不断&#xff0c;理还乱——UIResponder、UIGestureRecognizer、UIControl的响应优先级探究前言介绍UIResponderUIGestureRecognizerUIControl 正文UIGestur…...

GitHub Copilot的详细介绍

目录 主要功能&#xff1a; 示例用法&#xff1a; GitHub Copilot 的优缺点&#xff1a; 优点&#xff1a; 缺点&#xff1a; 如何使用 GitHub Copilot&#xff1f; 总结&#xff1a; GitHub Copilot 是一种基于人工智能的编程助手&#xff0c;由 GitHub 和 OpenAI 联合…...

opencv之阈值处理

文章目录 1. 阈值处理2. 阈值处理的基本原理3. 常见的阈值处理方法3.1 全局阈值&#xff08;Global Thresholding&#xff09;:3.2 自适应阈值&#xff08;Adaptive Thresholding&#xff09;:3.2.1 工作原理3.2.2 工作步骤3.2.3 适用场景3.2.4 优缺点自适应阈值的优点自适应阈…...

oracle startup失败,ORA-01078: failure in processing system parameters

SQL> startup ORA-01078: failure in processing system parameters LRM-00109: could not open parameter file /data/oracle/product/11.2.0/db_1/dbs/initorc1.ora 出错的原因可能是&#xff1a;文件名字不正确&#xff0c;文件权限不对&#xff0c;文件不存在&#x…...

【python因果推断库7】使用 pymc 模型的工具变量建模 (IV)2

目录 与普通最小二乘法 (OLS) 的比较 应用理论&#xff1a;政治制度与GDP 拟合模型&#xff1a;贝叶斯方法 多变量结果和相关性度量 结论 与普通最小二乘法 (OLS) 的比较 simple_ols_reg sk_lin_reg().fit(X.reshape(-1, 1), y)print("Intercept:", simple_ols_…...

【2024数模国赛赛题思路公开】国赛B题思路丨附可运行代码丨无偿自提

2024年国赛B题解题思路 问题 1: 抽样检测方案设计 【题目分析】 分析&#xff1a; 目标是设计一个高效的抽样检测方案&#xff0c;在尽量少的样本数量下&#xff0c;确保在高信度水平下做出正确的接受或拒收决策。需要处理两个不同的信度要求&#xff0c;这对样本量的计算提…...

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序(KNN分类器)

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序&#xff08;KNN分类器&#xff09; 文章目录 一、基本原理原理流程举个例子总结 二、实验结果三、核心代码四、代码获取五、总结 智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序&#x…...

使用udp进行通信

UDP chat 头文件 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <time…...

C#上位机使用Microsoft.Office.Interop.Excel和EPPlus库对Excel或WPS表格进行写操作

C#上位机使用Microsoft.Office.Interop.Excel和EPPlus库对Excel或WPS表格进行写操作 一、使用Microsoft.Office.Interop.Excel库 1、通过NuGet包管理器添加引用 按照下图中红框所示进行操作。 需要安装Microsoft.Office.Interop.Excel包 添加Microsoft Office 16.0 Object …...

java重点学习-redis

一.redis 穿透无中生有key&#xff0c;布隆过滤nul隔离 锁与非期解难题。缓存击穿过期key&#xff0c; 雪崩大量过期key&#xff0c;过期时间要随机。 面试必考三兄弟&#xff0c;可用限流来保底。 1.1 Redis的使用场景 根据自己简历上的业务进行回答 缓存穿透、击穿、雪崩、双…...

每日刷题(图论)

P1119 灾后重建 P1119 灾后重建 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路 看数据范围知道需要用到Floyd算法&#xff0c;但是道路是不能直接用的&#xff0c;需要等到连接道路的两个村庄重建好才可以使用&#xff0c;所以这需要按照时间依次加入中转点&#xff0c…...

Requestium - 将Requests和Selenium合并在一起的自动化测试工具

Requests 是 Python 的第三方库&#xff0c;主要用于发送 http 请求&#xff0c;常用于接口自动化测试等。 Selenium 是一个用于 Web 应用程序的自动化测试工具。Selenium 测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。 本篇介绍一款将 Requests 和 Seleniu…...

mysql和pg等数据库之间的数据迁移实战分享

mysql和pg等数据库之间的数据迁移是常见的问题&#xff1a;比如一开始使用Oracle&#xff0c;后来想使用mysql&#xff0c;而且需要把Oracle数据库的数据迁移到mysql里面&#xff1b;后期有想使用pg数据库&#xff0c;同时需要把Mysql数据库的数据迁移到pgl里面&#xff0c;等等…...

消息中间件都有哪些

RabbitMQ&#xff1a;这可是一个开源的消息代理软件&#xff0c;也叫消息中间件。它支持多种消息传递协议&#xff0c;可以轻松地在分布式系统中进行可靠的消息传递。 Kafka&#xff1a;Apache Kafka是一个分布式流处理平台&#xff0c;它主要用于处理实时数据流。Kafka的设计初…...

数据结构(3)内核链表

一、内核链表 内核链表是一种在操作系统内核中使用的数据结构&#xff0c;主要用于管理和组织内核对象。它是有头双向链表的一种实现。 内核链表的特点 双向链表: 内核链表的每个节点都包含指向前一个节点和后一个节点的指针&#xff0c;这使得在链表中进行插入和删除操作时更…...

Linux 硬件学习 s3c2440 arm920t蜂鸣器

1.查找手册时钟图&#xff0c;输入12m想要通过pll得到400m的信号 2.对比pll值&#xff0c;找到最近的为405&#xff0c;得到pll中mdiv为127&#xff0c;pdiv为2&#xff0c;sdiv为1 3.想要得到fclk400&#xff0c;hclk100&#xff0c;pclk50&#xff0c;对比分频比例&#xff0…...

提交保存,要做重复请求拦截,避免出现重复保存的问题

**问题&#xff1a;**前端ajax提交数据的时候&#xff0c;当频繁点击的时候&#xff0c;或者两个账号以相同数据创建的时候&#xff0c;会出现问题。 **处理办法&#xff1a;**前端拦截&#xff0c;防止重复提交数据&#xff0c;在上一次请求返回结果之后才允许提交第二次&…...

华为 HCIP-Datacom H12-821 题库 (3)

有需要题库的可以看主页置顶​​​​​​​ 1.运行 OSPF 协议的路由器在交互 DD 报文时&#xff0c;会使用以下哪一个参数选举主从关系&#xff1f; A、接口的 IP 地址 B、接口的 DR 优先级 C、Area ID D、Router ID 答案&#xff1a;D 解析&#xff1a; Router-ID 大的为主&a…...

spring-boot 事件

事件触发时机常用监听器描述ApplicationStartingEvent应用启动时LoggingApplicationListener&#xff1a;决定加载哪个日志系统ApplicationEnvironmentPreparedEvent创建Environment之后BootstrapApplicationListener&#xff1a;加载spring-cloud bootstrap配置文件&#xff1…...

合碳智能 × Milvus:探索化学合成新境界——逆合成路线设计

合碳智能&#xff08;C12.ai&#xff09;成立于2022年&#xff0c;致力于运用AI和具身智能技术&#xff0c;为药物研发实验室提供新一代智能化解决方案&#xff0c;推动实验室从自动化迈向智能化&#xff0c;突破传统实验模式与人员的依赖&#xff0c;解决效率和成本的瓶颈&…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...