UIResponser响应者控件
 
知识:
在iOS中不是任何对象都能处理事件,只有继承了UIResponser的对象才能接收并处理事件。我们称之为“响应者对象”
UIApplication,UIViewController,UIView都继承自UIResponser,因此它们都是响应者对象,都能够接收并处理事件
在以下三种情况下,不能接收事件
–与用户交互的属性设为NO
–hideen设为YES(隐藏)
–alpha=0(透明
可以重写hitTest:withEvent:方法设置事件处理的传递链,要么自己处理不往后传递,要么不处理往后传递给其他的view处理,甚至最后UIApplication都不处理就丢弃事件。
 
响应者类:

@interface UIResponder : NSObject

方法:

//获取下一个响应者

- (UIResponder*)nextResponder;

//当它放弃对象响应者,可以设置自身成为第一响应者,默认为NO

- (BOOL)canBecomeFirstResponder;

//设置第一响应者

- (BOOL)becomeFirstResponder;

//如果一个对象可以放弃对象响应者就返回YES,默认返回YES

- (BOOL)canResignFirstResponder;

//放弃第一响应者

- (BOOL)resignFirstResponder;

//是否是第一响应者

- (BOOL)isFirstResponder;

//触摸开始

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

//触摸移动

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

//触摸结束

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

//触摸取消

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

//运动开始

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;

//运动结束

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event ;

//运动取消

- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event ;

//远程控制接收事件

- (void)remoteControlReceivedWithEvent:(UIEvent *)event ;

//处理命令事件

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender ;

//初始化并处理命令事件

- (id)targetForAction:(SEL)action withSender:(id)sender;

属性:

//公共的事件撤销管理者

@property(nonatomic,readonly) NSUndoManager *undoManager;

@end

默认情况下,程序的每一个window都有一个undo管理器,它是一个用于管理undo和redo操作的共享对象。然而,响应链上的任何对象的类都可以有自定义undo管理器。例如,UITextField的实例的自定义管理器在文件输入框放弃第一响应者状态时会被清理掉。当需要一个undo管理器时,请求会沿着响应链传递,然后UIWindow对象会返回一个可用的实例。

按键调节器枚举(快捷键)

typedef NS_OPTIONS(NSInteger, UIKeyModifierFlags) {

UIKeyModifierAlphaShift ,         //Alppha+Shift键

UIKeyModifierShift        ,         //Shift键

UIKeyModifierControl    ,          //Control键

UIKeyModifierAlternate ,          //Alt键

UIKeyModifierCommand ,          //Command键

UIKeyModifierNumericPad ,       //Num键

} ;

按键命令类:

@interface UIKeyCommand : NSObject <NSCopying, NSSecureCoding>

属性:

//输入字符串

@property (nonatomic,readonly) NSString *input;

//按键调节器

@property (nonatomic,readonly) UIKeyModifierFlags modifierFlags;

方法:

//按指定调节器键输入字符串并设置事件

+ (UIKeyCommand *)keyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags) modifierFlags action:(SEL)action;

@end

响应者类的按键命令类类目:

@interface UIResponder (UIResponderKeyCommands)

//组合快捷键命令(装有多个按键的数组)

@property (nonatomic,readonly) NSArray *keyCommands;

@end

NSObject类的标准编辑事件响应类类目

@interface NSObject(UIResponderStandardEditActions)

//剪贴

- (void)cut:(id)sender ;

//复制

- (void)copy:(id)sender ;

//粘贴

- (void)paste:(id)sender ;

//选择

- (void)select:(id)sender ;

//选择全部

- (void)selectAll:(id)sender ;

//删除

- (void)delete:(id)sender;

//从左到右写入字符串(居左)

- (void)makeTextWritingDirectionLeftToRight:(id)sender ;

//从右到左写入字符串(居右)

- (void)makeTextWritingDirectionRightToLeft:(id)sender ;

//切换字体为黑体(粗体)

- (void)toggleBoldface:(id)sender;

//切换字体为斜体

- (void)toggleItalics:(id)sender ;

//给文字添加下划线

- (void)toggleUnderline:(id)sender ;

//增加字体大小

- (void)increaseSize:(id)sender ;

//减小字体大小

- (void)decreaseSize:(id)sender;

@end

响应者类的类目:

@interface UIResponder (UIResponderInputViewAdditions)

属性:

//键盘输入视图(系统默认的,可以自定义)

@property (nonatomic, readonly, retain) UIView *inputView;

//弹出键盘时附带的视图

@property (nonatomic, readonly, retain) UIView *inputAccessoryView;

//键盘输入视图控制器

@property (nonatomic, readonly, retain) UIInputViewController *inputViewController ;

//弹出键盘时附带的视图的视图控制器

@property (nonatomic, readonly, retain) UIInputViewController *inputAccessoryViewController;

//文本输入模式

@property (nonatomic, readonly, retain) UITextInputMode *textInputMode ;

//文本输入模式标识

@property (nonatomic, readonly, retain) NSString *textInputContextIdentifier;

方法:

//根据设置的标识清除指定的文本输入模式

+ (void)clearTextInputContextIdentifier:(NSString *)identifier;

//重新刷新键盘输入视图

- (void)reloadInputViews;

@end

注意:

UITextFields和UITextView有一个inputAccessoryView的属性,当你想在键盘上展示一个自定义的view时,你就可以设置该属性。你设置的view就会自动和键盘keyboard一起显示了。

需要注意的是,你所自定义的view既不应该处在其他的视图层里,也不应该成为其他视图的子视图。其实也就是说,你所自定义的view只需要赋给属性inputAccessoryView就可以了,不要再做其他多余的操作。

我们在使用UITextView和UITextField的时候,可以通过它们的inputAccessoryView属性给输入时呼出的键盘加一个附属视图,通常是UIToolBar,用于回收键盘。

inputView就是显示键盘的view,如果重写这个view则不再弹出键盘,而是弹出自己的view.如果想实现当某一控件变为第一响应者时不弹出键盘而是弹出我们自定义的界面,那么我们就可以通过修改这个inputView来实现,比如弹出一个日期拾取器。

inputView不会随着键盘出现而出现,设置了InputView只会当UITextField或者UITextView变为第一相应者时显示出来,不会显示键盘了。设置了InputAccessoryView,它会随着键盘一起出现并且会显示在键盘的顶端。InutAccessoryView默认为nil.

按键输入箭头指向

UIKIT_EXTERN NSString *const UIKeyInputUpArrow

UIKIT_EXTERN NSString *const UIKeyInputDownArrow

UIKIT_EXTERN NSString *const UIKeyInputLeftArrow

UIKIT_EXTERN NSString *const UIKeyInputRightArrow

UIKIT_EXTERN NSString *const UIKeyInputEscape

响应者类的类目:

@interface UIResponder (ActivityContinuation)

//用户活动

@property (nonatomic, retain) NSUserActivity *userActivity ;

//更新用户活动

- (void)updateUserActivityState:(NSUserActivity *)activity;

//恢复用户活动

- (void)restoreUserActivityState:(NSUserActivity *)activity;

@end

注意:

支持User Activities

从iOS 8起,苹果为我们提供了一个非常棒的功能,即Handoff。使用这一功能,我们可以在一部iOS设备的某个应用上开始做一件事,然后在另一台iOS设备上继续做这件事。Handoff的基本思想是用户在一个应用里所做的任何操作都可以看作是一个Activity,一个Activity可以和一个特定iCloud用户的多台设备关联起来。在编写一个支持Handoff的应用时,会有以下三个交互事件:

  1. 为将在另一台设备上继续做的事创建一个新的User Activity;
  2. 当需要时,用新的数据更新已有的User Activity;
  3. 把一个User Activity传递到另一台设备上。

为了支持这些交互事件,在iOS 8后,UIResponder类新增了几个方法,我们在此不讨论这几个方法的实际使用,想了解更多的话,可以参考 iOS 8 Handoff 开发指南 。我们在此只是简单描述一下这几个方法。

在UIResponder中,已经为我们提供了一个userActivity属性,它是一个NSUserActivity对象。因此我们在UIResponder的子类中不需要再去声明一个userActivity属性,直接使用它就行。其声明如下:

@property(nonatomic, retain) NSUserActivity *userActivity

由UIKit管理的User Activities会在适当的时间自动保存。一般情况下,我们可以重写UIResponder类的updateUserActivityState:方法来延迟添加表示User Activity的状态数据。当我们不再需要一个User Activity时,我们可以设置userActivity属性为nil。任何由UIKit管理的NSUserActivity对象,如果它没有相关的响应者,则会自动失效。

另外,多个响应者可以共享一个NSUserActivity实例。

上面提到的updateUserActivityState:是用于更新给定的User Activity的状态。其定义如下:

- (void)updateUserActivityState:(NSUserActivity *)activity

子类可以重写这个方法来按照我们的需要更新给定的User Activity。我们需要使用NSUserActivity对象的addUserInfoEntriesFromDictionary:方法来添加表示用户Activity的状态。

在我们修改了User Activity的状态后,如果想将其恢复到某个状态,则可以使用以下方法:

- (void)restoreUserActivityState:(NSUserActivity *)activity

子类可以重写这个方法来使用给定User Activity的恢复响应者的状态。系统会在接收到数据时,将数据传递给application:continueUserActivity:restorationHandler:以做处理。我们重写时应该使用存储在user activity的userInfo字典中的状态数据来恢复对象。当然,我们也可以直接调用这个方法。

 
 
 ❤️❤️❤️

UIView类中一些用于触摸事件和手势的常用方法:

//事件响应的测试:hit-test视图链事件处理

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

注释:

1.返回nil,表明对任何事件不做响应

2.返回self,对任何事件都响应

3.返回一个特定的view,将事件传递给响应者

//判断触摸点point在那个区域中

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

注释:

判断点是否被当前视图处理

1.返回YES:所有的点全处理

2.返回NO:所有的点全部处理

//将当前点或当前矩形区域的坐标转换到指定视图的坐标系

- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;

- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;

- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view;

- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;

举例验证事件处理的传递链如下:

1.在故事板的控制器视图View中拖入三个子控件,它们处于同一层级,顺序依次分别为按钮button和两个视图view1、view2,设置不同的背景颜色,绿色的为view1、深红色的为view2、紫色的为button。

此时,对触摸事件的处理传递链依次分别是:

view2-->button-->view-->ViewControler-->UIWindow-->Application-->丢弃

view1-->view-->ViewControler-->UIWindow-->Application-->丢弃

view-->ViewController-->UIWindow-->Application-->丢弃

       

2.为view1和view2分别创建两个类myView1和myView2,并将它们的控件与类对应,同时给button在控制器类中关联事件。

   (view1) (view2)

(button)

3.在ViewController.m文件中添加按钮事件的代码以重写触摸开始事件方法

//按钮事件处理

- (IBAction)buttonClicked:(UIButton *)sender
{
NSLog(@"点击了按钮");
}

//触摸开始事件处理

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"点击了白色的视图");
}

4.在子视图view1对应的类myView1.m文件中重写触摸开始事件处理,同时重写PointInside:withEvent:方法设置view1视图对触摸点事件是否处理。

//触摸开始事件处理

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"点击了绿色的视图");
}

//设置view1是否处理该触摸点事件

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return NO;
}

解释:判断点是否被当前视图处理

1.返回YES:所有的点全处理

2.返回NO:所有的点全部不处理

5、在子视图view2对应的类myView2.m文件中重写触摸开始事件处理,同时重写hitTest:withEvent:方法设置view2视图对触摸点事件处理的传递链。

//触摸开始事件处理

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"点击了红色视图");
}

//设置view2视图对触摸点事件处理的传递链

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
//查找button
UIButton *btn;
for (UIView *view in self.superview.subviews)
{
if (view.tag == )
{
btn = (UIButton *)view;
break;
}
} //判断触摸点point在那个区域中 //1.将当前点的坐标转换为按钮btn的坐标系
CGPoint btnPoint = [self convertPoint:point toView:btn]; //2.再判断
if ([btn pointInside:btnPoint withEvent:event])
{
return btn;
}
else if ([self pointInside:point withEvent:event])
{
return self;
} //正常的情况下
//return self.superview;
return [super hitTest:point withEvent:event];
}

解释:事件响应的测试

1.返回nil,表明对任何事件不做响应

2.返回self,对任何事件都响应

3.返回一个特定的view,将事件传递给响应者

6.演示结果如下:

<1>点击view2红色区域(不与紫色button局域重合的地方)时,view2视图对触摸点事件进行了处理

-- ::49.283 -responser[:] 点击了红色视图

<2>点击button紫色局域(包括重合局域)时,button按钮对触摸点事件都进行了处理。原因:点击button与view2没有重合的按钮局域时,button重写了TouchesBegan: withEvent:方法,它会对此局域的触摸事件做处理;点击button与view2重合的按钮局域时,本来view2视图在button的前面,view2应该先做处理的,但是由于view2类重写了hitTest:withEvent:方法,使得view2不对此局域的事件做处理,而是传递给了指定的视图button做处理。

-- ::48.385 -responser[:] 点击了按钮

<3>点击view1绿色局域和其他的白色局域时,都是当前控制器的视图view做了处理。原因:虽然view1的类重写了TouchesBegan: withEvent:方法用来处理触摸事件,但是又由于它有重写了pointInside:withEvent:方法并且返回值为NO,使自己不再对自己局域的任何触摸点事件做处理,而是把此事件直接向后传递给了它的父类View进行了处理。同时,控制器类的视图空白局域事件也是由View进行处理的,所以输出结果如下所示。

-- ::35.647 -responser[:] 点击了白色的视图

iOS:UIResponser控件的介绍(响应者)的更多相关文章

  1. 【iOS开发-88】事件传递原理解释哪个控件处理事件以及响应者链条的介绍

    一.触摸事件传递原理 (1)大的方向是:从父控件传递给子控件. --父控件会先检查自己能否接受事件的处理 --然后再看看触摸在不在自己的范围内 --假设在的话,就遍历子控件.看看有没有合适的子控件能够 ...

  2. iOS开发UI篇—UITableview控件简单介绍

    iOS开发UI篇—UITableview控件简单介绍 一.基本介绍 在众多移动应⽤用中,能看到各式各样的表格数据 . 在iOS中,要实现表格数据展示,最常用的做法就是使用UITableView,UIT ...

  3. iOS开发UI篇—Date Picker和UITool Bar控件简单介绍

    iOS开发UI篇—Date Picker和UITool Bar控件简单介绍 一.Date Picker控件 1.简单介绍: Date Picker显示时间的控件 有默认宽高,不用设置数据源和代理 如何 ...

  4. iOS开发基础-UITableView控件简单介绍

     UITableView 继承自 UIScrollView ,用于实现表格数据展示,支持垂直滚动.  UITableView 需要一个数据源来显示数据,并向数据源查询一共有多少行数据以及每一行显示什么 ...

  5. Swift UI控件详细介绍(上)

    UI控件 首先介绍一下AppDelegate.swift@UIApplicationMain 调用了OC中的UIApplicationMain函数:UIApplicationMain是iOS应用程序的 ...

  6. JS调用Android、Ios原生控件

    在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...

  7. 初识IOS,Label控件的应用。

    初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...

  8. IOS—UITextFiled控件详解

    IOS—UITextFiled控件详解 //初始化textfield并设置位置及大小 UITextField *text = [[UITextField alloc]initWithFrame:CGR ...

  9. [iOS基础控件 - 5.5] 代理设计模式 (基于”APP列表"练习)

    A.概述      在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果.功能      1.按钮点击后,显示为“已下载”,并且不 ...

随机推荐

  1. 微信小程序获取用户信息“授权失败”场景的处理

    很多的时候我们在处理小程序功能的时候需要用户获取用户信息,但是呢为了信息安全,用户不授权导致授权失败场景:但是小程序第二次不在启动授权信息弹层,为了用户体验,可以用以下方式处理: function i ...

  2. 运行ceph时,了解一下主要的进程。

    最简单ceph.conf配置如下: [global] fsid = 798ed076--429e-9e27-0ffccd60b56e mon_initial_members = ceph-node1 ...

  3. RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?

    https://www.zhihu.com/question/25912483?sort=created

  4. 树莓派与windows互传文件

    这是 meelo 原创的 玩转树莓派 系列文章 安装WinSCP 登录即可在左右两侧分别显示windows和树莓派中的文件 只需将文件从一侧拖到另一侧即可开始文件的传送

  5. php写入和读取文件内容

    function read_file($filename){ // $filename = "/usr/local/something.txt"; $handle = @fopen ...

  6. javascript高程笔记:逻辑与和逻辑或

    逻辑与和或 逻辑与 当 && 前后两个操作数都是布尔值,无可厚非,同时为true才为true.与其他强类型语言不同的是,javascript逻辑与前后的操作数可以应用于任何类型. 而且 ...

  7. 转:Spring学习笔记---Spring Security登录页

    转:http://axuebin.com/blog/2016/06/21/spring-security/?utm_source=tuicool&utm_medium=referral. 提示 ...

  8. HDU3466 Proud Merchants [背包]

    题目传送门 Proud Merchants Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/O ...

  9. Oracle基础了解

    数据库: 关系型数据库 select * from 表名 非关系型数据库(做不到复杂查询) 以对象的形式进行存储 {"aaa":"ccc"}---键值对 ora ...

  10. Web框架以及两种模式MVC,MTV

    一.Web框架的本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. import socket def handle_reques ...