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. 阻止父类的create,是无法阻止的

  2. hdu 1003(最大子段和)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  3. Fraction to Recurring Decimal——数值处理&&哈希表

    Given two integers representing the numerator and denominator of a fraction, return the fraction in ...

  4. AC日记——【模板】分块/带修改莫队(数颜色) 洛谷 P1903

    [模板]分块/带修改莫队(数颜色) 思路: 带修改莫队: (伏地膜xxy): 代码: #include <bits/stdc++.h> using namespace std; #defi ...

  5. Simditor学习--vuejs集成simditor

    唠叨 因为项目需要我自己研究了和集成在vue方便以后再使用,详情官方文档在这里.希望大家有好的建议提出让我继续改进. simditor介绍 Simditor 是团队协作工具 Tower 使用的富文本编 ...

  6. nginx 开启 gzip

    gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_comp_level 2; gzip_types text/plain applicatio ...

  7. CentOS7安装Pycharm后无法使用日常的快捷键

    1.在百度查了一圈,原来是vim在搞鬼 楼主在安装的时候,有另外添加了vim插件,所以ctrl +c之类的键都用不了,而且每次写py文件前都要先按insert键,真坑! 2.卸载pycharm里面的v ...

  8. Calendar类进行日期操作

    import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; /** * 测试日期类 * ...

  9. React Hooks useState为什么顺序很重要

    一个Function Component的state状态整体是作为memoizedState存在FIber中的. function执行时,首先取memoizedState第一个base state,作 ...

  10. 【Spring学习】在Spring+Maven环境中使用Junit Test

    在Spring+Maven环境中使用Junit Test 前言 以前我是很讨厌写测试代码的,总觉得测试用例是测试人员写的,现在想想自己真是Too yuong too simple,接触开发多了之后发现 ...