iosios 响应者链条分为链可以做什么

&nbsp>&nbsp
&nbsp>&nbsp
&nbsp>&nbsp
iOS-事件响应链
摘要:App通过响应者对象来接收和处理事件,响应者对象都是UIResponder的子类对象,常见的UIView,UIVieController和UIApplication都是UIResponder的子类.响应者接收事件原始数据之后必须进行事件处理或者转发给其他的响应者对象.当前App应用程接收到一个事件,UIKit会自动找到最合适的响应者对象,也就是常说的第一响应者.UIKit定义了响应者对象是如何进行事件转发的,常见的响应者链:事件响应者链.png第一响应者对于不同类型的事件,U
App通过响应者对象来接收和处理事件,响应者对象都是UIResponder的子类对象,常见的UIView,UIVieController和UIApplication都是UIResponder的子类.响应者接收事件原始数据之后必须进行事件处理或者转发给其他的响应者对象.
当前App应用程接收到一个事件,UIKit会自动找到最合适的响应者对象,也就是常说的第一响应者.UIKit定义了响应者对象是如何进行事件转发的,常见的响应者链:
事件响应者链.png
第一响应者
对于不同类型的事件,UIKit根据事件类型将事件对象传递给对应的响应者.
触摸事件:第一响应者就是触摸发生的视图.焦点事件:第一响应者就是具有焦点的容器控件.摇晃事件:需要自己或UIKit指定第一响应者.远程事件:需要自己或UIKit指定第一响应者.编辑菜单消息事件:需要自己或UIKit指定第一响应者.
加速度计,陀螺仪及磁强计有关的运动事件不遵循响应链.
触摸事件响应者
UIKit通过基于视图的hit-testing来确认触摸事件的发生.UIKit会按照视图的层级,逐层的按照触摸视图的位置和视图的bouds进行对比hitTest(_:with:)来寻找包含触摸事件最深层次的视图,这个视图就会成为触摸事件的第一响应者.
如果父视图不能响应触摸事件,那么所有的子视图也不会响应,即使子视图的位置超出父视图的bounds也不会响应.
&code&`- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *) // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
(BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *) // default returns YES if point is in bounds`&/code&
当视图hidden = YES,禁用用户操作(userInteractionEnabled=YES,透明度小于0.01的时候讲hitTest将不会执行.
响应者链通常是UIView组成的视图层级,假设第一响应者对象是UIView是视图控制器的根view,next responder是它的试图控制器,或者是它的父视图.
如果视图控制器是window的根控制器,next responder是window对象,如果控制器是被presented出来的,那么next responder是它的父控制器.最终找到UIWindow对象.
UIWiddow的next responder是UIApplication对象.
UIApplication的next responder是app delegate.
寻找顺序如下:&code&First Responser --& The Window --& The Application --& nil(丢弃)&/code&
关于事件响应者链有一个场景项目会经常遇到,按钮大小,经常会被产品经理要求按钮点击不灵敏,要求扩大点击区域.
1.自定义按钮,重写pointInside事件:&code&`@implementation FEButton
(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGRect bounds = self.
//若原热区小于44x44,则放大热区,否则保持原大小不变
CGFloat widthDelta = MAX(44.0 - bounds.size.width, 0);
CGFloat heightDelta = MAX(44.0 - bounds.size.height, 0);
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
NSLog(@&FlyElephant---被点击了:%@----点击的点:%@&,NSStringFromCGRect(bounds), NSStringFromCGPoint(point));
return CGRectContainsPoint(bounds, point);
@end`&/code&
2.项目中经常会用到圆角,这个时候有人告诉你,兄弟,我只想点击圆角内的区域响应事件,旁边的空白不希望响应.补习了基本的数学知识之后,代码修改如下:
&code&`@implementation CircleButton
(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGFloat halfWidth = self.bounds.size.width / 2;
CGFloat xDistance = point.x - halfW
CGFloat yDistance = point.y - halfW
CGFloat radius = sqrt(xDistance * xDistance + yDistance * yDistance);
NSLog(@&HaldWidth:%f---point:%@---x轴距离:%f---y轴距离:%f--半径:%f&,halfWidth,NSStringFromCGPoint(point),xDistance,yDistance,radius);
return radius &= halfW}
@end`&/code&
3.自己太多按钮,心好累,最终还是扩展UIButton,提供工作效率.
&code&`@interface UIButton (FlyElephant)
@property(nonatomic, assign) UIEdgeInsets hitTestEdgeI
@end`&/code&
&code&`#import &UIButton+FlyElephant.h&
import &objc/runtime.h&
@implementation UIButton (FlyElephant)
static const NSString *KEY_HIT_TEST_EDGE_INSETS = @&HitTestEdgeInsets&;
-(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets {NSValue *value = [NSValue value:&;hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)];objc_setAssociatedObject(self, &;KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}
-(UIEdgeInsets)hitTestEdgeInsets {NSValue *value = objc_getAssociatedObject(self, &;KEY_HIT_TEST_EDGE_INSETS);if(value) {UIEdgeInsets edgeI [value getValue:&;edgeInsets]; return edgeI}else {return UIEdgeInsetsZ}}
(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) {return [super pointInside:point withEvent:event];}
CGRect relativeFrame = self.CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets);
return CGRectContainsPoint(hitFrame, point);}
@end`&/code&
UI测试代码:&code&`- (void)setUp {
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
bgView.backgroundColor = [UIColor redColor];
[self.view addSubview:bgView];
FEButton *button = [[FEButton alloc] initWithFrame:CGRectMake(20, 20, 20, 20)];
button.backgroundColor = [UIColor greenColor];
[bgView addSubview:button];
UIView *bgView1 = [[UIView alloc] initWithFrame:CGRectMake(100, 300, 100, 100)];
bgView1.backgroundColor = [UIColor redColor];
[self.view addSubview:bgView1];
CircleButton *button1 = [[CircleButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
button1.backgroundColor = [UIColor greenColor];
button1.clipsToBounds = YES;
button1.layer.cornerRadius = 50;
[button1 addTarget:self action:@selector(buttonAction1:) forControlEvents:UIControlEventTouchUpInside];
[bgView1 addSubview:button1];
UIView *bgView2 = [[UIView alloc] initWithFrame:CGRectMake(100, 500, 100, 100)];
bgView2.backgroundColor = [UIColor redColor];
[self.view addSubview:bgView2];
UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(20, 20, 20, 20)];
button2.backgroundColor = [UIColor greenColor];
button2.hitTestEdgeInsets = UIEdgeInsetsMake(-20, -20, -20, -20);
[button2 addTarget:self action:@selector(buttonAction2:) forControlEvents:UIControlEventTouchUpInside];
[bgView2 addSubview:button2];
(void)buttonAction1:(UIButton *)sender {NSLog(@&FlyElephant---圆形扩大点击区域&);}
(void)buttonAction2:(UIButton *)sender {NSLog(@&Runtime扩大点击&);}`&/code&
FlyElephant.png
参考链接https://developer.apple.com/documentation/uikit/understanding_event_handling_responders_and_the_responder_chainhttps://stackoverflow.com/questions/808503/uibutton-making-the-hit-area-larger-than-the-default-hit-areahttp://www.cnblogs.com/wengzilin/p/4249847.html?utm_source=tuicool&;utm_medium=referral
以上是的内容,更多
的内容,请您使用右上方搜索功能获取相关信息。
若你要投稿、删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内给你回复。
云服务器 ECS
可弹性伸缩、安全稳定、简单易用
&40.8元/月起
预测未发生的攻击
&24元/月起
邮箱低至5折
推荐购买再奖现金,最高25%
&200元/3月起
你可能还喜欢
你可能感兴趣
阿里云教程中心为您免费提供
iOS-事件响应链相关信息,包括
的信息,所有iOS-事件响应链相关内容均不代表阿里云的意见!投稿删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内答复
售前咨询热线
支持与服务
资源和社区
关注阿里云
InternationaliOS开发封装一个可以响应超链接的label——基于RCLabel的交互扩展
iOS开发封装一个可以响应超链接的label——基于RCLabel的交互扩展
iOS开发封装一个可以响应超链接的label——基于RCLabel的交互扩展
iOS系统是一个十分注重用户体验的系统,在iOS系统中,用户交互的方案也十分多,然而要在label中的某部分字体中添加交互行为确实不容易的,如果使用其他类似Button的控件来模拟,文字的排版又将是一个解决十分困难的问题。
iOS开发封装一个可以响应超链接的label——基于RCLabel的交互扩展
iOS系统是一个十分注重用户体验的系统,在iOS系统中,用户交互的方案也十分多,然而要在label中的某部分字体中添加交互行为确实不容易的,如果使用其他类似Button的控件来模拟,文字的排版又将是一个解决十分困难的问题。这个问题的由来是项目中的一个界面中有一些广告位标签,而这些广告位的标签却是嵌在文本中的,当用户点击文字标签的位置时,会跳转到响应的广告页。
CoreText框架和一些第三方库可以解决这个问题,但直接使用CoreText十分复杂,第三方库多注重于富文本的排版,对类似文字超链接的支持亦不是特别简洁,我们可以借助一些第三方的东西进行针对性更强,更易用的封装。
RCLabel是一个第三方的将html字符串进行文本布局的工具,代码十分轻巧,并且其是基于CoreText框架的,其原生性和扩展性十分强。在以前的一篇博客中,我将RCLabel进行了一些改进,使其支持异步加载远程图片,并且提供了更加简洁的面向应用的方法,博客地址如下:
扩展于RCLabel的支持异步加载网络图片的富文本引擎的设计: 。
本篇博文,将在其基础上,完成设计一个可以支持文本超链接的文字视图。
二、视图类与模型类的设计
RCLabel的核心之处在于将HTML文本转换为富文本布局视图,因此我们可以将要显示的文本编程html字符串,将其可以进行用户交互的部分进行html超链接关联,RCLabel就检测到我们点击的区域进行响应逻辑的回调。设计类如下:
@class YHBaseLinkingLabelM
@protocol YHBaseLinkingLabelProtocol &NSObject&
-(void)YHBaseLinkingLabelClickLinking:(YHBaseLinkingLabelModel *)
-(void)YHBaseLinkingLabelSizeChange:(CGSize)
@interface YHBaseLinkingLabel : YHBaseView
@property(nonatomic,strong)NSArray&YHBaseLinkingLabelModel *& * textA
@property(nonatomic,weak)id&YHBaseLinkingLabelProtocol&
@property(nonatomic,strong)UIColor * textC
@property(nonatomic,strong)UIColor * linkC
@property(nonatomic,assign)NSUInteger fontS
@property(nonatomic,assign)int linkingFontS
@property(nonatomic,assign)BOOL isShowUnderL
@interface YHBaseLinkingLabel()&YHBaseHtmlViewProcotop&
@implementation YHBaseLinkingLabel
YHBaseHtmlView * _
- (instancetype)init
self = [super init];
if (self) {
_label = [[YHBaseHtmlView alloc]init];
[self addSubview:_label];
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(@0);
make.trailing.equalTo(@0);
make.top.equalTo(@0);
make.bottom.equalTo(@0);
_label.delegate=
- (instancetype)initWithCoder:(NSCoder *)coder
self = [super initWithCoder:coder];
if (self) {
_label = [[YHBaseHtmlView alloc]init];
[self addSubview:_label];
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(@0);
make.trailing.equalTo(@0);
make.top.equalTo(@0);
make.bottom.equalTo(@0);
_label.delegate=
- (instancetype)initWithFrame:(CGRect)frame
self = [super initWithFrame:frame];
if (self) {
_label = [[YHBaseHtmlView alloc]init];
[self addSubview:_label];
[_label mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(@0);
make.trailing.equalTo(@0);
make.top.equalTo(@0);
make.bottom.equalTo(@0);
_label.delegate=
-(void)setTextArray:(NSArray&YHBaseLinkingLabelModel *& *)textArray{
_textArray = textA
NSString * htmlString = [self transLinkingDataToHtmlStr:textArray];
[_label reSetHtmlStr:htmlString];
-(void)setTextColor:(UIColor *)textColor{
_textColor = textC
_label.fontColor = textC
-(void)setLinkColor:(UIColor *)linkColor{
_linkColor = linkC
_label.linkingColor = linkC
-(void)setFontSize:(NSUInteger)fontSize{
_fontSize = fontS
[_label setFontSize:(int)fontSize];
-(void)setLinkingFontSize:(int)linkingFontSize{
_linkingFontSize = linkingFontS
[_label setLinkingSize:linkingFontSize];
-(void)setIsShowUnderLine:(BOOL)isShowUnderLine{
_isShowUnderLine = isShowUnderL
[_label setShowUnderLine:isShowUnderLine];
-(NSString *)transLinkingDataToHtmlStr:(NSArray&YHBaseLinkingLabelModel *& *)data{
NSMutableString * mutStr = [[NSMutableString alloc]init];
for (int i=0; i&data. i++) {
YHBaseLinkingLabelModel * model = data[i];
if (!model.linking) {
[mutStr appendString:model.text];
[mutStr appendString:@"&a href="];
[mutStr appendString:model.linking];
[mutStr appendString:@"&"];
[mutStr appendString:model.text];
[mutStr appendString:@"&/a&"];
return mutS
#pragma mark delegate
-(void)YHBaseHtmlView:(YHBaseHtmlView *)htmlView ClickLink:(NSString *)url{
for (YHBaseLinkingLabelModel * model in _textArray) {
if ([model.linking isEqualToString:url]) {
if ([self.delegate respondsToSelector:@selector(YHBaseLinkingLabelClickLinking:)]) {
[self.delegate YHBaseLinkingLabelClickLinking:model];
-(void)YHBaseHtmlView:(YHBaseHtmlView *)htmlView SizeChanged:(CGSize)size{
if ([self.delegate respondsToSelector:@selector(YHBaseLinkingLabelSizeChange:)]) {
[self.delegate YHBaseLinkingLabelSizeChange:size];
上面我们有用到一个YHBaseLinkingLabelModel类,这个类进行了链接与字符的映射,设计如下:
@interface YHBaseLinkingLabelModel : YHBaseModel
@property(nonatomic,strong)NSString *
@property(nonatomic,strong)NSString *
YHBaseHtmlView类是对RCLabel的一层封装,其中也对RCLabel进行了一些优化和改动,代码较多且在上篇博客中有介绍,这里不再多做解释了。
在ViewController中写如下代码进行使用:
- (void)viewDidLoad {
[super viewDidLoad];
YHBaseLinkingLabel * label = [[YHBaseLinkingLabel alloc]initWithFrame:CGRectMake(100, 100, 200, 100)];
NSMutableArray * array = [[NSMutableArray alloc]init];
for (int i=0; i&6; i++) {
YHBaseLinkingLabelModel * model = [[YHBaseLinkingLabelModel alloc]init];
if (!(i%2)) {
model.text =[NSString stringWithFormat:@"第%d个标签",i];
model.linking = [NSString stringWithFormat:@"第%d个标签",i];
model.text = @",不能点得文字,";
[array addObject:model];
label.textColor = [UIColor blackColor];
label.linkColor = [UIColor purpleColor];
label.fontSize = 15;
label.linkingFontSize = 17;
label.isShowUnderLine=YES;
label.delegate=
label.textArray =
[self.view addSubview:label];
-(void)YHBaseLinkingLabelClickLinking:(YHBaseLinkingLabelModel *)model{
NSLog(@"%@",model.linking);
运行效果如下:
效果不错,并且十分简单易用,对吧。
用云栖社区APP,舒服~
【云栖快讯】云栖社区技术交流群汇总,阿里巴巴技术专家及云栖社区专家等你加入互动,老铁,了解一下?&&
大数据开发套件(Data IDE),提供可视化开发界面、离线任务调度运维、快速数据集成、多人...
是基于语音识别、语音合成、自然语言理解等技术,为企业在多种实际应用场景下,赋予产品“能听、会...
移动测试(Mobile Testing)是为广大企业客户和移动开发者提供真机测试服务的云平台...
为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效...
阿里中间件云大使iOS面试 重零单排:什么是响应链,它是怎么工作的_百度知道
iOS面试 重零单排:什么是响应链,它是怎么工作的
我有更好的答案
响应链设计模式,解决的是request和response两者之间的关系。我们知道,在面向对象(甚至是面向过程中)的领域中,客户/服务器的请求服务是一个永恒的模式。事实上,客户/服务器模式,也是一种抽象的机制。请求者只需要要完成某件事只需要发出请求,其他的事情由服务器完成。
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。iOS UIResponder响应链是怎么设计和解耦的? - 知乎有问题,上知乎。知乎作为中文互联网最大的知识分享平台,以「知识连接一切」为愿景,致力于构建一个人人都可以便捷接入的知识分享网络,让人们便捷地与世界分享知识、经验和见解,发现更大的世界。2被浏览74分享邀请回答0添加评论分享收藏感谢收起写回答iOS UI事件传递与响应者链
招聘信息:
响应者链响应者对象:继承自UIResponder的对象称之为响应者对象。UIApplication、UIWindow、UIViewController和所有继承UIView的UIKit类都直接或间接的继承自UIResponder。UIResponder一般响应以下几种事件:触摸事件(touch handling)、点按事件(press handling)、加速事件和远程控制事件:触摸事件(touch&handling)
-&(void)touchesBegan:(NSSet&*)touches&withEvent:(nullable&UIEvent&*)
-&(void)touchesMoved:(NSSet&*)touches&withEvent:(nullable&UIEvent&*)
-&(void)touchesEnded:(NSSet&*)touches&withEvent:(nullable&UIEvent&*)
-&(void)touchesCancelled:(NSSet&*)touches&withEvent:(nullable&UIEvent&*)
-&(void)touchesEstimatedPropertiesUpdated:(NSSet&*)touches&NS_AVAILABLE_IOS(9_1);
点按事件(press&handling)&NS_AVAILABLE_IOS(9_0)
-&(void)pressesBegan:(NSSet&*)presses&withEvent:(nullable&UIPressesEvent&*)event&NS_AVAILABLE_IOS(9_0);
-&(void)pressesChanged:(NSSet&*)presses&withEvent:(nullable&UIPressesEvent&*)event&NS_AVAILABLE_IOS(9_0);
-&(void)pressesEnded:(NSSet&*)presses&withEvent:(nullable&UIPressesEvent&*)event&NS_AVAILABLE_IOS(9_0);
-&(void)pressesCancelled:(NSSet&*)presses&withEvent:(nullable&UIPressesEvent&*)event&NS_AVAILABLE_IOS(9_0);
-&(void)motionBegan:(UIEventSubtype)motion&withEvent:(nullable&UIEvent&*)event&NS_AVAILABLE_IOS(3_0);
-&(void)motionEnded:(UIEventSubtype)motion&withEvent:(nullable&UIEvent&*)event&NS_AVAILABLE_IOS(3_0);
-&(void)motionCancelled:(UIEventSubtype)motion&withEvent:(nullable&UIEvent&*)event&NS_AVAILABLE_IOS(3_0);
远程控制事件
-&(void)remoteControlReceivedWithEvent:(nullable&UIEvent&*)event&NS_AVAILABLE_IOS(4_0);响应者链:由多个响应者组合起来的链条,就叫做响应者链。它表示了每个响应者之间的联系,并且可以使得一个事件可选择多个对象处理响应者链.png假设触摸了initial view,1.第一响应者就是initial view即initial view首先响应touchesBegan:withEvent:方法,接着传递给橘黄色的view2.橘黄色的view开始响应touchesBegan:withEvent:方法,接着传递给蓝绿色view3.蓝绿色view响应touchesBegan:withEvent:方法,接着传递给控制器的view4.控制器view响应touchesBegan:withEvent:方法,控制器传递给了窗口5.窗口再传递给application如果上述响应者都不处理该事件,那么事件被丢弃事件的产生和传递当一个触摸事件产生的时候,我们的程序是如何找到第一响应者的呢?事件的产生传递.png当你点击了屏幕会产生一个触摸事件,消息循环(runloop)会接收到触摸事件放到消息队列里,UIApplication会会从消息队列里取事件分发下去,首先传给UIWindow,UIWindow会使用hitTest:withEvent:方法找到此次触摸事件初始点所在的视图,找到这个视图之后他就会调用视图的touchesBegan:withEvent:方法来处理事件。hitTest:withEvent:查找过程hitTestview过程.png图片中view等级
&&&&[ViewA&addSubview:ViewB];
&&&&[ViewA&addSubview:ViewC];
&&&&[ViewB&addSubview:ViewD];
&&&&[ViewB&addSubview:ViewE];点击viewE:1.A 是UIWindow的根视图,首先对A进行hitTest:withEvent:2.判断A的userInteractionEnabled,如果为NO,A的hitTest:withEvent返回3.pointInside:withEvent:方法判断用户点击是否在A的范围内,显然返回YES4.遍历A的子视图B和C,由于从后向前遍历,因此先查看C,调用C的hitTest:withEvent方法:pointInside:withEvent:方法判断用户点击是否在C的范围内,不在返回NO,C对应的hitTest:withEvent: 方法return nil;再查看B,调用B的hitTest:withEvent方法:pointInside:withEvent:判断用户点击是否在B的返回内,在返回YES遍历B的子视图D和E,从后向前遍历,先查看E,调用E的hitTest:withEvent方法:pointInside:withEvent:方法 判断用户点击是否在E的范围内,在返回YES,E没有子视图,因此E对应的hitTest:withEvent方法返回E,再往前回溯,就是B的hitTest:withEvent方法返回E,因此A的hitTest:withEvent方法返回E。至此,点击事件的第一响应者就找到了。如果hitTest:withEvent: 找到的第一响应者view没有处理该事件,那么事件会沿着响应者链向上传递->父视图->视图控制器,如果传递到最顶级视图还没处理事件,那么就传递给UIWindow处理,若window对象也不处理->交给UIApplication处理,如果UIApplication对象还不处理,就丢弃该事件。事件流程.png注意:控件不能响应的情况1.userInteractionEnabled = NO2.hidden = YES3.透明度 alpha 小于等于0.014.子视图超出了父视图区域子视图超出父视图,不响应的原因:因为父视图的pointInside:withEvent:方法返回了NO,就不会遍历子视图了。可以重写pointInside:withEvent:方法解决此问题。作者:小湾子链接:http://www.jianshu.com/p/1a來源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量4556点击量2428点击量2074点击量2043点击量1885点击量1809点击量1738点击量1727点击量1654
&2018 Chukong Technologies,Inc.
京公网安备89

我要回帖

更多关于 ios 响应者链条分为 的文章

 

随机推荐