UIView 中的控件事件穿透 Passthrough 的实现

【手势隔层透传】iOS viewA被viewB遮挡,如何让viewA依然响应添加的pan平移手势 目录实践参考系统响应阶段APP响应触摸事件触摸 事件 响应者触摸触摸事件响应者寻找最佳响应者(Hit-Testing)视图如何判断自己能否响应触摸事件?寻找最佳响应者的原理hitTest:withEvent:自定义hitTest:withEvent:触摸事件的响应响应链中的事件传递规则UIResponder、UIGestureRecognizer、UIControl的优先级UIGestureRecognizerUIControl 实践 场景描述: viewA上的80%被viewB遮挡 viewA上添加了pa 阅读详情

我们在有多个 UIView 层叠时,比如一个按钮被一个 UIView 遮盖时,想要在点击最上层的 UIView 时能触发按钮的相应事件,我们该如何实现呢,初步可以想到几种办法:

1. 把按钮上层的所有 UIView 的 userInteractionEnabled 属性设置为 NO,要是 UIView 有自己的交互事件该如何办呢?而且这个 userInteractionEnabled 不能动态设置,等到点击后决定设置它的 NO 是没用的

2. UIView 接受到点击事件后主动去触发下面按钮的点击,这时的关题有三,按钮没有点击过程中的交换效果、多层 UIView 时不切实际,逐层下传吗、还有就是其他双击、三击或别的手势如何处理

我也一直被前面两种方式纠缠着,同时也让 UIPopoverController 的 NSArray *passthroughViews 属性提醒着,因为对于 UIPopoverController,设置到它的 passthoughViews 属性中的控件事件可以完全从 UIDimmingView 下透出来。但苦于不可能看到 UIPopoverController 的源码,还是后面一而再的 Google 终于发现了 UIView 的方法:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;   // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system

只要实现了最顶层的 UIView 的 hitTest 方法,在某些情况返回下层的某个按钮实例,即相当于把那个按钮的事件透出来了,比如在点击落在该按钮上时,不管这个按钮在 UIView 下多少层都可以把它挖出来。

先看效果图:

 

三个图分别是:

1. 所见到的,按钮被半透明红色 View 遮住了一部分
2. 可点击未遮住的按钮部分,可看到按钮被点下未抬起的效果
3. 在红色的 View 中点击按钮被遮住部分,同样触发了按钮的相应事件,且有中间效果,也就是说按钮穿透出来了

再看代码实现,有两部分代码,分别是 ViewController 和  CustomController

ViewController.h

01
02
03
04
05
06
07
08
09
10
11
12
13
14
//
//  ViewController.h
 
//
//  Created by Unmi on 11/15/11.
//  Copyright (c) 2011 http://unmi.cc. All rights reserved.
//
 
#import <UIKit/UIKit.h>
 
@interface ViewController : UIViewController {
}
 
@end

ViewController.h

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//
//  ViewController.m
//
//  Created by Unmi on 11/15/11.
//  Copyright (c) 2011 http://unmi.cc. All rights reserved.
//
 
#import "ViewController.h"
#import "CustomView.h"
 
@implementation ViewController{
     UIButton *passthroughButton;
}
 
#pragma mark - View lifecycle
 
- ( void )viewDidLoad
{
     [ super viewDidLoad];
 
     passthroughButton = [ UIButton buttonWithType: UIButtonTypeRoundedRect ];
     [passthroughButton setTitle:@ "Passthrough" forState: UIControlStateNormal ];
     [ self .view addSubview:passthroughButton];
     passthroughButton.frame = CGRectMake(20, 50, 120, 28);
     [passthroughButton release];
     
     CustomView *customView = [[CustomView alloc] initWithFrame:CGRectMake(80, 10, 300, 200)];
     customView.backgroundColor = [ UIColor colorWithRed:1 green:0 blue:0 alpha:.5];
     customView.passthroughViews = [ NSArray arrayWithObject:passthroughButton];
     [ self .view addSubview:customView];
     [customView release];
}
 
- ( void )dealloc {
     [ super dealloc];
}
@end

CustomView.h

01
02
03
04
05
06
07
08
09
10
11
12
13
//
//  CustomView.h
//  TestPopover
//
//  Created by Unmi on 2/19/12.
//  Copyright (c) 2012 http://unmi.cc. All rights reserved.
//
 
#import <UIKit/UIKit.h>
 
@interface CustomView : UIView
@property ( nonatomic , copy ) NSArray *passthroughViews;
@end

CustomView.m

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//
//  CustomView.m
//
//  Created by Unmi on 2/19/12.
//  Copyright (c) 2012 http://unmi.cc. All rights reserved.
//
 
#import "CustomView.h"
 
@interface CustomView()
-( BOOL ) isPassthroughView: ( UIView *) view;
@end
 
@implementation CustomView{
     BOOL testHits;
}
 
@synthesize passthroughViews=_passthroughViews;
 
-( UIView *) hitTest:(CGPoint)point withEvent:( UIEvent *)event{
     if (testHits){
         return nil ;
     }
     
     if (! self .passthroughViews
         || ( self .passthroughViews && self .passthroughViews.count == 0)){
         return self ;
     } else {
         
         UIView *hitView = [ super hitTest:point withEvent:event];
         
         if (hitView == self ) {
             //Test whether any of the passthrough views would handle this touch
             testHits = YES ;
             CGPoint superPoint = [ self .superview convertPoint:point fromView: self ];
             UIView *superHitView = [ self .superview hitTest:superPoint withEvent:event];
             testHits = NO ;
             
             if ([ self isPassthroughView:superHitView]) {
                 hitView = superHitView;
             }
         }
         
         return hitView;
     }
}
 
- ( BOOL )isPassthroughView:( UIView *)view {
     
     if (view == nil ) {
         return NO ;
     }
     
     if ([ self .passthroughViews containsObject:view]) {
         return YES ;
     }
     
     return [ self isPassthroughView:view.superview];
}             
 
-( void ) dealloc{
     self .passthroughViews = nil ;
}
 
@end

关键要理解 hitTest 方法的作用,可参考:

1. http://blog.sina.com.cn/s/blog_677089db01012wpg.html
2. https://github.com/werner77/WEPopover

本文链接 http://unmi.cc/uiview-event-passthrough/, 来自隔叶黄莺 Unmi Blog

多层UIview触摸事件的穿透(非重叠子控件互不影响) 在项目中经常遇到这样的需求,屏幕被分成几个区域,并且每个区域都有很多不定时外部事件,要求层次分明互不影响,这个时候对UIview的触摸事件控制就很重要,下面是一个例子: 1.创建一个UIView的基础类,PBaseView,它的.m文件实现: @implementation PBaseView - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ UIView *hitView = [super hitTest:point.. 阅读详情

相关推荐

Qwen2-7B微调实战:LoRA+QLoRA单卡3090指令微调全指南

大语言模型微调是将通用基座适配垂直场景的核心技术,其本质是通过参数高效方法(如LoRA)在冻结主干权重的前提下注入领域知识。Qwen2系列凭借中英双语原生词表、高比例中文训练语料及阿里云百炼平台深度集成,在中文法律、金融、政务等长文本理解任务中展现出显著工程优势。本文聚焦Qwen2-7B这一消费级显卡友好型模型,详解基于LoRA与QLoRA的指令微调全流程,覆盖数据清洗规范、CUDA 12.1+PyTorch 2.3环境避坑、r=8/alpha=16超参配置、百炼平台零代码微调与本地Hugging Face

weixin_34062469的博客 356

UIView 响应链 点击穿透 捕获

https://www.jianshu.com/p/f6aff12fc08buiview - Event handling for iOS - how hitTest:withEvent: and pointInside:withEvent: are related? - Stack Overflow

407

imageView点击穿透事件示例

imageView 点击穿透 根据图片的透明度判断点击位置

让uiview可被点击事件穿透

在view的.m文件中 实现以下方法 - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ UIView *hitView = [super hitTest:point withEvent:event]; if(hitView == self){ return nil; } ...

u013857988的专栏 3639

USB3.0 Type-B连接器SSTX/SSRX信号定义常见错误与硬件设计避坑指南

本文详细解析了USB3.0 Type-B连接器中SSTX/SSRX信号的定义标准与常见设计错误。针对连接器厂商图纸可能出现的信号标识错误,提供了实用的排查方法和硬件设计避坑指南,帮助工程师避免因引脚定义颠倒导致的通信降级或故障,确保USB3.0高速传输的稳定性。

gg901的博客 1262

Android dex, odex, oat, vdex, art文件介绍

下图可以简化将Java源转换为OAT的过程: .dex Dalvik虚拟机字节码文件 .vdex 其中包含APK的未压缩DEX代码,以及一些旨在加快验证速度的元数据 .odex .oat // JIT,Just-in-time,即时编译,边运行边编译; // AOT,Ahead Of Time,提前编译,指运行前编译。 其中包含APK中已经过AOT编译的方法代码。 原始DEX文件(例如classes.dex)被转换为另一个包含本机代码的文件。这个新文件通常具有.odex。.oat扩展名,并由ELF格式

he980725866的博客 3618

better-scroll(安装、使用方式、插件(参数)属性、事件方法)

文章目录 better-scroll 介绍 better-scroll 是什么 起步 滚动原理 better-scroll 在 MVVM 框架的应用 安装 NPM script 加载 选项 / 基础 startX startY scrollX scrollY freeScroll directionLockThreshold eventPassthrough click dblclick(v1.12.0+) tap b

AIWWY的博客 5039

AMD MI50 Linux ROCm 6.4 手动编译与大模型推理实战

GPU加速计算是现代AI推理的核心基础,其性能依赖于硬件架构、驱动栈与运行时环境的深度协同。ROCm作为AMD开源GPU计算平台,采用‘自下而上’的Linux生态集成路径,强调对上游内核、编译器与固件的强耦合。MI50基于Vega 20(gfx900)架构,虽具备32GB HBM2高带宽显存与14.7 TFLOPS FP16算力,但因ROCm官方支持策略转向CDNA架构,自6.5版本起被移出支持列表,仅ROCm 6.4仍提供实验性兼容——这使其成为Linux下部署私有大模型的关键‘最后一班船’。本文围绕MI

weixin_32770423的博客 366

移动端如何实现横向和纵向都滚动,better-scroll实现横向和纵向双向滚动

因项目需要,要实现横向和纵向双向滚动的功能,自己手写了一个结果ios和android不兼容。。。 后来发现大神的better-scroll可以实现,但也是频频踩坑,这几个配置间有冲突,搞不好还不能实现双向滚动,结果要加班,哈哈 那接下来就总结一下我实践成功的方法,先看效果图 开始讲解 环境和版本 这个是在vue中自己封装的组件 "vue": "^2.5.2", "better-scroll": "^1.15.2", 组件 <template> <div> &l

zyf_baby的博客 1795

大白映射 宝马Esys编程设码映射、USB设备映射

大白映射,宝马Esys设码编程、USB设备映射

denson0394的博客 4794

浅谈python反序列化漏洞

0x01 python序列化与反序列化 Python 的序列化和反序列化是将一个类对象向字节流转化从而进行存储和传输,然后使用的时候再将字节流转化回原始的对象的一个过程。python中的序列化操作是通过pickle模块,而该模块主要包含l dumps将dict转化为str格式,loads将str格式转化为dict格式。 dump和load与文件操作结合起来, pickle.dump(obj, f...

Lethe's Blog 3219

View事件穿透,解决方法

原因: 多个View重叠,点击事件穿透,点击顶层的view底层的view响应了 处理方法: 在顶层消费点击事件,传递不到底层 1.   可以使用setOnClickListener不响应点击事件、 2.   setOnTouchListener返回值变为true 3.  给控件添加属性:android:clickable="true" 4.   使用Android Touch事件处理

u014250518的博客 2479

体系结构学习-6-超标量处理器

 MIPS32-5段流水线采用了指令级并行方式(5个流水段同时运行5条指令)提升系统吞吐率,是一种标量处理器(CPI≥1CPI \ge 1CPI≥1),但是一个周期一条指令以及无法满足现代计算机需求了。 超标量处理器(Superscalar) 1、基本思想:增强指令集并行,让每个周期执行更多指令,实现 CPI<1CPI<1CPI<1 。(IPC=1/CPIIPC = 1...

qq_40891899的博客 1210

横向iscroll阻止纵向浏览器滚动条

参考iscroll官方文档, options.eventPassthrough 有些时候你想保留原生纵向的滚动条但想为横向滚动条增加iScroll功能(比如走马灯)。设置这个属性为true并且iScroll区域只将影响横向滚动,纵向滚动将滚动整个页面。 在移动设备上访问event passthrough demo。注意,这个值也可以设置为'horizontal',其作用和上面介绍的相反(横向...

only_neo的博客 1031

DLMS—Cryptographic algorithms—(Green-Book)加密算法

密码学是数学的一个分支,基于数据的转换,并且可以用来提供多种安全服务:保密性、数据完整性、认证、授权和不可否认性。密码学依赖于两个基本组成部分:算法(或密码学方法)和密钥。算法是一个数学函数,而密钥是在转换过程中使用的参数。密码算法和密钥用于对数据应用密码保护(例如,加密数据或生成数字签名),以及移除或检查保护(例如,解密加密的数据或验证数字签名)。密码哈希函数:这类函数不需要密钥(尽管它们可以以使用密钥的模式使用)。哈希函数通常用作算法的一个组成部分,以提供安全服务。见9.2.3.2节。对称密钥算法。

一个bug是bug,多个bug能work 1706

2023年12月青少年C/C++软件编程(三级)等级考试试卷及答案解析

有一批易感人群住在网格状的宿舍区内,宿舍区为n*n的矩阵,每个格点为一个房间,房间里可能住人,也可能空着。在第一天,有些房间里的人得了流感,以后每天,得流感的人会使其邻居传染上流感,(已经得病的不变),空房间不会传染。第一行一个数字n,n不超过100,表示有n*n的宿舍房间。接下来的n行,每行n个字符,’.’表示第一天该房间住着健康的人,’#’表示该房间空着,’@’表示第一天该房间住着得流感的人。输出为一行,表达式的值。任给两个正整数N、M,求一个最小的正整数a,使得a和(M-a)都是N的因子。

长春高老师编程 1510

基于 vue +better scroll滑动切换页面 并支持下拉刷新案例

也是公司项目 ,内部app的资讯模块整改,改是不可能改的,之前还是用jquery。感觉越改越混乱,还是重做。就仿着今日头条、等资讯页面做了一个dome,话不多说,先看效果! 效果看完,感觉还行的话,接着就往下看开启爬坑之路! 先打一个无偿广告 上图的gif 是通过LICEcap 软件录屏制作的!下载地址:官网地址,支持window mac ,无插件 无广告 完全免费!确实好用,比起国内的...

黄治文的博客 1615

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android 上层的View透传/不透传 点击事件 到下层

点击事件 透传/不透传到下层控件

Goals1989的博客 1275

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

better-scroll 2.X手册

使用 基础滚动 如果你只需要一个拥有基础滚动能力的列表,只需要引入 core。 import BScroll from '@better-scroll/core' let bs = new BScroll('.wrapper', { // ...... 详见配置项 }) 增强型滚动 如果你需要一些额外的 feature。比如 pull-up,你需要引入额外的插件,详情查看插件。 import BScroll from '@better-scroll/core' import Pullup from '

Motong_Lee的博客 1671

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

iOS 使点击事件穿透透明的UIView

通过实例讲解,如图(三个深灰色按钮处于同一个contentView中): 悬浮的三个按钮下方有一个可以点击的灰色区域,但是点击按钮之间的透明区域, 这三个按钮的contentView会响应这个点击事件,这时候需要让这个contentView不响应这个点击事件。 解决方法如下(将此方法增加到这个contentView类中即可): ...

weixin_30276935的博客 735
上一篇: Views概念总结
下一篇: ARC简介以及工程中ARC与非ARC的混合
focusjava
博客等级 码龄14年 127粉丝 528原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值