1. 程式人生 > >ios開發 之 UIResponder詳解

ios開發 之 UIResponder詳解

        在iOS中UIResponder類是專門用來響應使用者的操作處理各種事件的,包括觸控事件(Touch Events)、運動事件(Motion Events)、遠端控制事件(Remote Control Events)。我們知道UIApplication、UIView、UIViewController這幾個類是直接繼承自UIResponder,所以這些類都可以響應事件。當然我們自定義的繼承自UIView的View以及自定義的繼承自UIViewController的控制器都可以響應事件。本文將詳細介紹UIResponder類。

一、使用詳解

1、通過響應者鏈查詢檢視的檢視控制器

/**
 *  查詢檢視的檢視控制器
 *
 *  @param view 檢視
 *
 *  @return 返回檢視的控制器
 */
- (UIViewController *)getControllerFromView:(UIView *)view {
    // 遍歷響應者鏈。返回第一個找到檢視控制器
    UIResponder *responder = view;
    while ((responder = [responder nextResponder])){
        if ([responder isKindOfClass: [UIViewController class]]){
            return (UIViewController *)responder;
        }
    }
    // 如果沒有找到則返回nil
    return nil;
}

       通過響應鏈查詢檢視控制器,nextResponder獲取下一個響應者,響應者順序為:


2、設定與取消第一響應者

//
//  ZMFirstResponderView.m
//  ZMResponderDemo
//
//  Created by ZengZhiming on 2017/5/12.
//  Copyright © 2017年 菜鳥基地. All rights reserved.
//

#import "ZMFirstResponderView.h"

@implementation ZMFirstResponderView

/** 演示設定為第一響應者 */
- (void)setBecomeFirstResponder {
    // 判斷物件是否已經是第一響應者
    if ([self isFirstResponder]) {
        return;
    }
    // 判斷物件是否允許成為第一響應者
    if ([self canBecomeFirstResponder]) {
        // 設定成為第一響應者
        [self becomeFirstResponder];
    }
}

/** 演示放棄第一響應者 */
- (void)setResignFirstResponder {
    // 判斷物件是否不是第一響應者
    if (![self isFirstResponder]) {
        return;
    }
    // 判斷物件是否允許放棄第一響應者
    if ([self canResignFirstResponder]) {
        // 設定放棄第一響應者
        [self resignFirstResponder];
    }
}

/** 重寫方法,允許物件成為第一響應者 */
- (BOOL)canBecomeFirstResponder {
    return YES;
}

@end
      UIView預設不允許設定為第一響應者,因此設定UIView為第一響應者需要重寫canBecomeFirstResponder方法並返回YES。 設定為第一響應者後,物件則可以接受遠端控制事件進行處理(如耳機線控)。UITextField、UITextView成為第一響應者後會彈出輸入鍵盤,取消第一響應者則會隱藏輸入鍵盤。

3、觸控相關方法,一般用於響應螢幕觸控

/** 手指按下時響應 */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    NSLog(@"--->手指按下時響應");
}

/** 手指移動時響應 */
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    [super touchesMoved:touches withEvent:event];
    NSLog(@"--->手指移動時響應");
}

/** 手指擡起時響應 */
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    NSLog(@"--->手指擡起時響應");
}

/** 觸控取消(意外中斷, 如:電話, Home鍵退出等) */
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    NSLog(@"--->取消觸控響應");
}

4、加速相關方法,一般用於搖一搖、運動事件監聽等

/** 開始加速 */
- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0) {
    [super motionBegan:motion withEvent:event];
    NSLog(@"--->開始加速");
}

/** 結束加速 */
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0) {
    [super motionEnded:motion withEvent:event];
    NSLog(@"--->結束加速");
}

/** 加速取消(意外中斷, 如:電話, Home鍵退出等) */
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0) {
    [super motionCancelled:motion withEvent:event];
    NSLog(@"--->加速取消");
}

5、遠端控制方法,一般用於耳機線控

//
//  ZMAudioView.m
//  ZMResponderDemo
//
//  Created by ZengZhiming on 2017/5/12.
//  Copyright © 2017年 菜鳥基地. All rights reserved.
//

#import "ZMAudioView.h"
#import <AVFoundation/AVFoundation.h>

@implementation ZMAudioView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 啟動接受遠端事件
        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
        // 設定成為第一響應者
        [self becomeFirstResponder];
        // 播放一段靜音檔案,使APP獲取音訊的控制權
        NSURL *audioURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"mute_60s" ofType:@"mp3"]];
        AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
        [audioPlayer play];
    }
    return self;
}

/** 允許物件成為第一響應者 */
- (BOOL)canBecomeFirstResponder {
    return YES;
}

/** 遠端控制事件響應 */
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
    NSLog(@"--->耳機線控響應");
}

- (void)dealloc {
    // 停止接受遠端事件
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    // 放棄第一響應者
    [self resignFirstResponder];
}

@end

耳機線控要注意三點要素:
(1)啟動接受遠端事件:[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
(2)設定成為第一響應者(UIViewController,AppDelegate中不需要設定)

// 設定成為第一響應者
[self becomeFirstResponder];

/** 允許物件成為第一響應者 */
- (BOOL)canBecomeFirstResponder {
    return YES;
}

(3)獲取音訊的控制權

// 播放一段靜音檔案,使APP獲取音訊的控制權
NSURL *audioURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"mute_60s" ofType:@"mp3"]];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
[audioPlayer play];

6、在UILabel中實現長按選單(複製、貼上等)

//
//  ZMMenuLabel.m
//  ZMResponderDemo
//
//  Created by ZengZhiming on 2017/5/15.
//  Copyright © 2017年 菜鳥基地. All rights reserved.
//

#import "ZMMenuLabel.h"

@implementation ZMMenuLabel

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 啟用使用者互動
        self.userInteractionEnabled = YES;
        // 新增長按手勢
        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressMenu:)];
        longPressGesture.minimumPressDuration = 0.2;
        [self addGestureRecognizer:longPressGesture];
    }
    return self;
}

/** 允許物件成為第一響應者 */
- (BOOL)canBecomeFirstResponder {
    return YES;
}

/** 長按響應 */
- (void)longPressMenu:(UILongPressGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateBegan) {
        // 設定成為第一響應者
        [self becomeFirstResponder];
        // 顯示選單
        UIMenuController *menuCtrl = [UIMenuController sharedMenuController];
        [menuCtrl setTargetRect:self.frame inView:self.superview];
        [menuCtrl setMenuVisible:YES animated:YES];
    }
}

/** 返回需要顯示的選單按鈕 */
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    // 只顯示覆制、貼上按鈕
    if (action == @selector(copy:) || action == @selector(paste:)) {
        return YES;
    }
    return NO;
}

/** 實現複製方法 */
- (void)copy:(id)sender {
    UIPasteboard *paste = [UIPasteboard generalPasteboard];
    paste.string = self.text;
}

/** 實現貼上方法 */
- (void)paste:(id)sender {
    UIPasteboard *paste = [UIPasteboard generalPasteboard];
    self.text = paste.string;
}

@end
為UILabel新增長按選單需要注意幾點:

(1)啟用使用者互動:self.userInteractionEnabled = YES;

(2)在顯示選單之前設定物件成為第一響應者(UIViewController,AppDelegate中不需要設定)

/** 允許物件成為第一響應者 */
- (BOOL)canBecomeFirstResponder {
    return YES;
}

// 設定成為第一響應者
[self becomeFirstResponder];

(3)返回選單需要顯示的按鈕,並重寫實現對應方法

/** 返回需要顯示的選單按鈕 */
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    // 只顯示覆制、貼上按鈕
    if (action == @selector(copy:) || action == @selector(paste:)) {
        return YES;
    }
    return NO;
}

/** 實現複製方法 */
- (void)copy:(id)sender {
    UIPasteboard *paste = [UIPasteboard generalPasteboard];
    paste.string = self.text;
}

/** 實現貼上方法 */
- (void)paste:(id)sender {
    UIPasteboard *paste = [UIPasteboard generalPasteboard];
    self.text = paste.string;
}
(4)註冊長按手勢,顯示選單
// 新增長按手勢
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressMenu:)];
longPressGesture.minimumPressDuration = 0.2;
[self addGestureRecognizer:longPressGesture];

/** 長按響應 */
- (void)longPressMenu:(UILongPressGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateBegan) {
        // 設定成為第一響應者
        [self becomeFirstResponder];
        // 顯示選單
        UIMenuController *menuCtrl = [UIMenuController sharedMenuController];
        [menuCtrl setTargetRect:self.frame inView:self.superview];
        [menuCtrl setMenuVisible:YES animated:YES];
    }
}

7、使用NSUndoManager實現畫板撤銷/重做功能

/** ==============ZMDrawingBoardView.h檔案=================== */

#import <UIKit/UIKit.h>

/** 畫板View */
@interface ZMDrawingBoardView : UIView

@end


/** 劃線Model */
@interface ZMLineModel : NSObject

@property (nonatomic) CGPoint begin;
@property (nonatomic) CGPoint end;

@end


/** ==============ZMDrawingBoardView.m檔案=================== */

#import "ZMDrawingBoardView.h"

/** 畫板View */
@interface ZMDrawingBoardView ()

@property (nonatomic, strong) ZMLineModel *currentLine;
@property (nonatomic, strong) NSMutableArray<ZMLineModel *> *toucheArray;

@end

@implementation ZMDrawingBoardView


- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initSubView];
        self.backgroundColor = [UIColor whiteColor];
        self.toucheArray = [NSMutableArray array];
    }
    return self;
}

/** 繪製畫板 */
- (void)drawRect:(CGRect)rect {
    // 獲得上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 設定樣式
    CGContextSetLineCap(context, kCGLineCapSquare);
    // 設定寬度
    CGContextSetLineWidth(context, 5.0);
    // 設定顏色
    CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor]);
    
    for (ZMLineModel *line in self.toucheArray) {
        // 開始繪製
        CGContextBeginPath(context);
        // 移動畫筆到起點
        CGContextMoveToPoint(context, line.begin.x, line.begin.y);
        // 新增下一點
        CGContextAddLineToPoint(context, line.end.x, line.end.y);
        // 繪製完成
        CGContextStrokePath(context);
    }
}

/** 劃線開始 */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 標記開始撤銷分組
    [self.undoManager beginUndoGrouping];
    
    for (UITouch *touch in touches) {
        // 記錄起始點
        CGPoint locTouch = [touch locationInView:self];
        _currentLine = [[ZMLineModel alloc] init];
        _currentLine.begin = locTouch;
        _currentLine.end = locTouch;
    }
    
}

/** 劃線移動 */
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    for (UITouch *touch in touches) {
        // 新增線條
        CGPoint locTouch = [touch locationInView:self];
        _currentLine.end = locTouch;
        [self addLine:_currentLine];
        // 當前線條
        _currentLine = [[ZMLineModel alloc] init];
        _currentLine.begin = locTouch;
        _currentLine.end = locTouch;
    }
}

/** 劃線結束 */
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 結束標記撤銷分組
    [self.undoManager endUndoGrouping];
}

/** 新增劃線 */
- (void)addLine:(ZMLineModel *)line
{
    // 新增劃線並重繪畫板
    [self.toucheArray addObject:line];
    [self setNeedsDisplay];
    // 註冊撤銷方法
    [[self.undoManager prepareWithInvocationTarget:self] removeLine:line];
}

/** 移除劃線 */
- (void)removeLine:(ZMLineModel *)line
{
    if ([self.toucheArray containsObject:line]) {
        // 移除劃線並重繪畫板
        [self.toucheArray removeObject:line];
        [self setNeedsDisplay];
        // 註冊撤銷方法
        [[self.undoManager prepareWithInvocationTarget:self] addLine:line];
    }
}

/** 撤銷按鈕點選響應 */
- (void)undoButtonAction:(id)sender {
    if ([self.undoManager canUndo]) {
        [self.undoManager undo];
    }
}

/** 重做按鈕點選響應 */
- (void)redoButtonAction:(id)sender {
    if ([self.undoManager canRedo]) {
        [self.undoManager redo];
    }
}

/** 初始化子控制元件 */
- (void)initSubView {
    // 撤銷按鈕
    UIButton *undoButton = [UIButton buttonWithType:UIButtonTypeSystem];
    undoButton.frame = CGRectMake(0, 64, 70, 50);
    [undoButton setTitle:@"undo撤銷" forState:UIControlStateNormal];
    [undoButton sizeToFit];
    [undoButton addTarget:self action:@selector(undoButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:undoButton];
    // 重做按鈕
    UIButton *redoButton = [UIButton buttonWithType:UIButtonTypeSystem];
    redoButton.frame = CGRectMake(CGRectGetWidth(self.frame)-70, 64, 70, 50);
    [redoButton setTitle:@"redo重做" forState:UIControlStateNormal];
    [redoButton sizeToFit];
    [redoButton addTarget:self action:@selector(redoButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:redoButton];
}

@end
實現撤銷/重做注意以下幾點:

(1)在呼叫方法時需要添加註冊一個對應的撤銷方法

// 註冊撤銷方法
[[self.undoManager prepareWithInvocationTarget:self] removeLine:line];
(2)撤銷/ 重做只需要呼叫undoManager中的相應方法即可
/** 撤銷按鈕點選響應 */
- (void)undoButtonAction:(id)sender {
    if ([self.undoManager canUndo]) {
        [self.undoManager undo];
    }
}

/** 重做按鈕點選響應 */
- (void)redoButtonAction:(id)sender {
    if ([self.undoManager canRedo]) {
        [self.undoManager redo];
    }
}
(3)如果需要多個動作一起撤銷則需要標記分組
    // 標記開始撤銷分組
    [self.undoManager beginUndoGrouping];
    // 結束標記撤銷分組
    [self.undoManager endUndoGrouping];

8、自定義快捷鍵

//
//  ZMKeyCommandView.m
//  ZMResponderDemo
//
//  Created by ZengZhiming on 2017/5/17.
//  Copyright © 2017年 菜鳥基地. All rights reserved.
//

#import "ZMKeyCommandView.h"

@implementation ZMKeyCommandView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 設定成為第一響應者
        [self becomeFirstResponder];
    }
    return self;
}

/** 允許物件成為第一響應者 */
- (BOOL)canBecomeFirstResponder {
    return YES;
}

/** 返回快捷命令陣列 */
-(NSArray<UIKeyCommand *> *)keyCommands {
    return @[
             [UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:UIKeyModifierShift action:@selector(pressedShiftAndEscapeKey:) discoverabilityTitle:@"自定義[Shift+Esc]快捷鍵"],
             [UIKeyCommand keyCommandWithInput:@"a" modifierFlags:UIKeyModifierShift action:@selector(pressedShiftAndAKey:) discoverabilityTitle:@"自定義[Shift+A]快捷鍵"]
             ];
}

/** Shift+Esc快捷命令響應 */
-(void)pressedShiftAndEscapeKey:(UIKeyCommand *)keyCommand {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:keyCommand.discoverabilityTitle message:[NSString stringWithFormat:@"按下快捷輔鍵:[%@]", keyCommand.input] delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil];
    [alertView show];
}

/** Shift+A快捷命令響應 */
-(void)pressedShiftAndAKey:(UIKeyCommand *)keyCommand {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:keyCommand.discoverabilityTitle message:[NSString stringWithFormat:@"按下快捷輔鍵:[%@]", keyCommand.input] delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil];
    [alertView show];
}

@end
自定義快捷鍵需要注意兩點:

(1)設定物件成為第一響應者(UIViewController,AppDelegate中不需要設定)

// 設定成為第一響應者
[self becomeFirstResponder];

/** 允許物件成為第一響應者 */
- (BOOL)canBecomeFirstResponder {
    return YES;
}
(2)重寫keyCommands返回快捷命令組合
/** 返回快捷命令陣列 */
-(NSArray<UIKeyCommand *> *)keyCommands {
    return @[
             [UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:UIKeyModifierShift action:@selector(pressedShiftAndEscapeKey:) discoverabilityTitle:@"自定義[Shift+Esc]快捷鍵"],
             [UIKeyCommand keyCommandWithInput:@"a" modifierFlags:UIKeyModifierShift action:@selector(pressedShiftAndAKey:) discoverabilityTitle:@"自定義[Shift+A]快捷鍵"]
             ];
}

9、自定義UITextField輸入鍵盤 

//
//  ZMCustomInputView.m
//  ZMResponderDemo
//
//  Created by ZengZhiming on 2017/5/18.
//  Copyright © 2017年 菜鳥基地. All rights reserved.
//

#import "ZMCustomInputView.h"

#define MAIN_SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width   //!< 螢幕的Width

@interface ZMCustomInputView ()

@property (nonatomic, strong) UITextField *textField;
@property (nonatomic, strong) UIView *customInputView;
@property (nonatomic, strong) UIToolbar *customAccessoryView;

@end

@implementation ZMCustomInputView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 新增TextField
        [self addSubview:self.textField];
    }
    return self;
}

/** 懶載入textField */
- (UITextField *)textField {
    if (!_textField) {
        // 初始化textField
        _textField = [[UITextField alloc]initWithFrame:CGRectMake(50, 100, MAIN_SCREEN_WIDTH - 100, 30)];
        _textField.borderStyle = UITextBorderStyleRoundedRect;
        _textField.placeholder = @"測試";
        // 設定自定義鍵盤View
        _textField.inputView = self.customInputView;
        _textField.inputAccessoryView = self.customAccessoryView;
    }
    return _textField;
}

/** 懶載入customInputView */
- (UIView *)customInputView {
    if (!_customInputView) {
        _customInputView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, MAIN_SCREEN_WIDTH, 220)];
        _customInputView.backgroundColor = [UIColor lightGrayColor];
        UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 100, MAIN_SCREEN_WIDTH, 40)];
        label.textAlignment = NSTextAlignmentCenter;
        label.text = @"自定義inputView";
        [_customInputView addSubview:label];
    }
    return _customInputView;
}

/** 懶載入customAccessoryView */
- (UIToolbar *)customAccessoryView {
    if (!_customAccessoryView) {
        _customAccessoryView = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, MAIN_SCREEN_WIDTH, 40)];
        _customAccessoryView.barTintColor = [UIColor orangeColor];
        UIBarButtonItem *space = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
        UIBarButtonItem *done = [[UIBarButtonItem alloc]initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(done)];
        [_customAccessoryView setItems:@[space, space, done]];
    }
    return _customAccessoryView;
}

/** 響應完成按鈕 */
- (void)done {
    [self.textField resignFirstResponder];
}


@end

二、UIResponder.h詳解

//
//  UIResponder.h
//  ZMHeaderFile
//
//  Created by ZengZhiming on 2017/4/18.
//  Copyright © 2017年 菜鳥基地. All rights reserved.
//
//  詳解 UIResponder.h
//  Version iOS 10.3
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKitDefines.h>
#import <UIKit/UIEvent.h>

NS_ASSUME_NONNULL_BEGIN

@class UIPress;
@class UIPressesEvent;

#pragma mark - UIResponderStandardEditActions協議定義

@protocol UIResponderStandardEditActions <NSObject>
@optional
/** 剪下事件 */
- (void)cut:(nullable id)sender NS_AVAILABLE_IOS(3_0);
/** 複製事件 */
- (void)copy:(nullable id)sender NS_AVAILABLE_IOS(3_0);
/** 貼上事件 */
- (void)paste:(nullable id)sender NS_AVAILABLE_IOS(3_0);
/** 選擇事件 */
- (void)select:(nullable id)sender NS_AVAILABLE_IOS(3_0);
/** 全選事件 */
- (void)selectAll:(nullable id)sender NS_AVAILABLE_IOS(3_0);
/** 刪除事件 */
- (void)delete:(nullable id)sender NS_AVAILABLE_IOS(3_2);
/** 從左到右寫入字串(居左) */
- (void)makeTextWritingDirectionLeftToRight:(nullable id)sender NS_AVAILABLE_IOS(5_0);
/** 從右到左寫入字串(居右) */
- (void)makeTextWritingDirectionRightToLeft:(nullable id)sender NS_AVAILABLE_IOS(5_0);
/** 切換字型為黑體(粗體) */
- (void)toggleBoldface:(nullable id)sender NS_AVAILABLE_IOS(6_0);
/** 切換字型為斜體 */
- (void)toggleItalics:(nullable id)sender NS_AVAILABLE_IOS(6_0);
/** 給文字新增下劃線 */
- (void)toggleUnderline:(nullable id)sender NS_AVAILABLE_IOS(6_0);

/** 增加字型大小 */
- (void)increaseSize:(nullable id)sender NS_AVAILABLE_IOS(7_0);
/** 減小字型大小 */
- (void)decreaseSize:(nullable id)sender NS_AVAILABLE_IOS(7_0);

@end

#pragma mark - UIResponder類定義

NS_CLASS_AVAILABLE_IOS(2_0) @interface UIResponder : NSObject <UIResponderStandardEditActions>

#pragma mark - 響應者相關方法

/** 獲取下一個響應者 */
#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly, nullable) UIResponder *nextResponder;
#else
- (nullable UIResponder *)nextResponder;
#endif

/** 是否允許成為第一響應者。預設返回NO */
#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly) BOOL canBecomeFirstResponder;
#else
- (BOOL)canBecomeFirstResponder;
#endif
/** 設定成為第一響應者 */
- (BOOL)becomeFirstResponder;

/** 是否允許放棄第一響應者。預設返回YES */
#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly) BOOL canResignFirstResponder;
#else
- (BOOL)canResignFirstResponder;
#endif
/** 設定放棄第一響應者 */
- (BOOL)resignFirstResponder;

/** 判斷物件是否是第一響應者 */
#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly) BOOL isFirstResponder;
#else
- (BOOL)isFirstResponder;
#endif

#pragma mark - 觸控相關方法,一般用於響應螢幕觸控
/** 手指按下時響應 */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
/** 手指移動時響應 */
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
/** 手指擡起時響應 */
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
/** 取消(意外中斷, 如:電話, 系統警告窗等) */
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
/** 3DTouch響應(iOS9.1後使用) */
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);

#pragma mark - 深按相關方法,一般用於遙控器按鍵響應
/** 手指按壓開始時響應 */
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
/** 手指按壓位置移動時響應 */
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
/** 手指擡起接受按壓時響應 */
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
/** 按壓取消(意外中斷, 如:電話, 系統警告窗等) */
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);

#pragma mark - 加速相關方法,一般用於搖一搖、運動事件監聽等
/** 開始加速 */
- (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);

/** 返回UIMenuController需要顯示的控制元件(如:複製,貼上等) */
- (BOOL)canPerformAction:(SEL)action withSender:(nullable id)sender NS_AVAILABLE_IOS(3_0);

/** 返回響應的操作目標物件 */
- (nullable id)targetForAction:(SEL)action withSender:(nullable id)sender NS_AVAILABLE_IOS(7_0);

/** 獲取響應鏈就近共享撤消管理 */
@property(nullable, nonatomic,readonly) NSUndoManager *undoManager NS_AVAILABLE_IOS(3_0);

@end

/** 快捷主鍵列舉 */
typedef NS_OPTIONS(NSInteger, UIKeyModifierFlags) {
    UIKeyModifierAlphaShift     = 1 << 16,  //!< Alpha+Shift鍵.
    UIKeyModifierShift          = 1 << 17,  //!< Shift鍵.
    UIKeyModifierControl        = 1 << 18,  //!< Control鍵.
    UIKeyModifierAlternate      = 1 << 19,  //!< Alt鍵.
    UIKeyModifierCommand        = 1 << 20,  //!< Command鍵.
    UIKeyModifierNumericPad     = 1 << 21,  //!< Num鍵.
} NS_ENUM_AVAILABLE_IOS(7_0);

#pragma mark - 快捷鍵物件

NS_CLASS_AVAILABLE_IOS(7_0) @interface UIKeyCommand : NSObject <NSCopying, NSSecureCoding>

/** 初始化物件 */
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/** 初始化物件 */
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

/** 獲取快捷輔鍵(如快捷命令【Command+A】中的 A 鍵) */
@property (nonatomic,readonly) NSString *input;
/** 獲取快捷主鍵(如快捷命令【Command+A】中的 Command 鍵) */
@property (nonatomic,readonly) UIKeyModifierFlags modifierFlags;
/** 顯示給使用者的快捷鍵標題 */
@property (nullable,nonatomic,copy) NSString *discoverabilityTitle NS_AVAILABLE_IOS(9_0);

/** 建立一個快捷鍵命令 */
+ (UIKeyCommand *)keyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)modifierFlags action:(SEL)action;

/** 建立一個快捷鍵命令 */
+ (UIKeyCommand *)keyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)modifierFlags action:(SEL)action discoverabilityTitle:(NSString *)discoverabilityTitle NS_AVAILABLE_IOS(9_0);

@end

#pragma mark - 響應快捷命令

@interface UIResponder (UIResponderKeyCommands)
/** 返回快捷鍵命令陣列 */
@property (nullable,nonatomic,readonly) NSArray<UIKeyCommand *> *keyCommands NS_AVAILABLE_IOS(7_0);
@end

@class UIInputViewController;
@class UITextInputMode;
@class UITextInputAssistantItem;

#pragma mark - 輸入檢視

@interface UIResponder (UIResponderInputViewAdditions)

/** 鍵盤輸入檢視(系統預設的,可以自定義) */
@property (nullable, nonatomic, readonly, strong) __kindof UIView *inputView NS_AVAILABLE_IOS(3_2);
/** 彈出鍵盤時附帶的檢視 */
@property (nullable, nonatomic, readonly, strong) __kindof UIView *inputAccessoryView NS_AVAILABLE_IOS(3_2);

/** 輸入助手配置鍵盤的快捷方式欄時使用 */
@property (nonnull, nonatomic, readonly, strong) UITextInputAssistantItem *inputAssistantItem NS_AVAILABLE_IOS(9_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;

/** 鍵盤輸入檢視控制器 */
@property (nullable, nonatomic, readonly, strong) UIInputViewController *inputViewController NS_AVAILABLE_IOS(8_0);
/** 彈出鍵盤時附帶的檢視的檢視控制器 */
@property (nullable, nonatomic, readonly, strong) UIInputViewController *inputAccessoryViewController NS_AVAILABLE_IOS(8_0);

/** 文字輸入模式 */
@property (nullable, nonatomic, readonly, strong) UITextInputMode *textInputMode NS_AVAILABLE_IOS(7_0);

/** 文字輸入模式標識 */
@property (nullable, nonatomic, readonly, strong) NSString *textInputContextIdentifier NS_AVAILABLE_IOS(7_0);
/** 根據設定的標識清除指定的文字輸入模式 */
+ (void)clearTextInputContextIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(7_0);

/** 重新重新整理鍵盤輸入檢視 */
- (void)reloadInputViews NS_AVAILABLE_IOS(3_2);

@end

/** 特殊快捷輔鍵定義 */
UIKIT_EXTERN NSString *const UIKeyInputUpArrow         NS_AVAILABLE_IOS(7_0); //!< 上按鍵.
UIKIT_EXTERN NSString *const UIKeyInputDownArrow       NS_AVAILABLE_IOS(7_0); //!< 下按鍵.
UIKIT_EXTERN NSString *const UIKeyInputLeftArrow       NS_AVAILABLE_IOS(7_0); //!< 左按鍵.
UIKIT_EXTERN NSString *const UIKeyInputRightArrow      NS_AVAILABLE_IOS(7_0); //!< 右按鍵
UIKIT_EXTERN NSString *const UIKeyInputEscape          NS_AVAILABLE_IOS(7_0); //!< Esc按鍵.

#pragma mark - 響應者活動

@interface UIResponder (ActivityContinuation)
/** 使用者活動 */
@property (nullable, nonatomic, strong) NSUserActivity *userActivity NS_AVAILABLE_IOS(8_0);
/** 更新使用者活動 */
- (void)updateUserActivityState:(NSUserActivity *)activity NS_AVAILABLE_IOS(8_0);
/** 恢復使用者活動 */
- (void)restoreUserActivityState:(NSUserActivity *)activity NS_AVAILABLE_IOS(8_0);
@end

NS_ASSUME_NONNULL_END


 原文地址:http://blog.csdn.net/zeng_zhiming/article/details/71747881