前言

咱们在前面一篇文章中,对在iOS视觉处理相关结构进行了简介。

在本篇文章主要针对 其间 的 UIKit结构的中心关键,进行一个回忆,作为一个复习和总结。

UIKit结构 是iOS应用程序开发的根底结构之一,也是iOS开发中的一个中心结构。它供给了一系列的类和组件,经过UIKit,开发者能够快速构建各种界面元素、完结用户交互动画作用。

现在Apple也推出了 SwiftUI 用于 构建界面,完结用户交互 和 动画。我比较倾向于 在写 灵动岛 适配的时分运用 SwiftUI ,做应用的业务页面的时分,运用 UIKit结构

整篇文章的内容主要包含:

一、UIKit中的中心目标

UIKit结构的责任

咱们先引入一段官方对UIKit的介绍

UIKit provides a variety of features for building apps, including components you can use to construct the core infrastructure of your iOS, iPadOS, or tvOS apps. The framework provides the window and view architecture for implementing your UI, the event-handling infrastructure for delivering Multi-Touch and other types of input to your app, and the main run loop for managing interactions between the user, the system, and your app.

02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】

UIKit also includes support for animations, documents, drawing and printing, text management and display, search, app extensions, resource management, and getting information about the current device. You can also customize accessibility support, and localize your app’s interface for different languages, countries, or cultural regions.

UIKit works seamlessly with theSwiftUIframework, so you can implement parts of your UIKit app in SwiftUI or mix interface elements between the two frameworks. For example, you can place UIKit views and view controllers inside SwiftUI views, and vice versa.

To build a macOS app, you can useSwiftUIto create an app that works across all of Apple’s platforms, or useAppKitto create an app for Mac only. Alternatively, you can bring your UIKit iPad app to the Mac withMac Catalyst.

Important

Use UIKit classes only from your app’s main thread or main dispatch queue, unless otherwise indicated in the documentation for those classes. This restriction particularly applies to classes that derive fromUIResponderor that involve manipulating your app’s user interface in any way.

简扼地概括一下UIKit结构的责任便是:

  • 经过UIKit,开发者能够快速构建各种界面元素、完结用户交互动画作用等。
    • 构建UI界面
      • 用于完结 UI 的窗口和视图架构
    • 交互事情处理
      • 用于向应用程序供给多点触控其他类型输入的事情处理根底设施
      • 用于办理用户体系应用程序之间交互的主运转循环
    • 动画作用等
      • UIKit 还包含对动画、文档、绘图和打印、文本办理和显现、搜索、应用程序扩展、资源办理以及获取有关当时设备的信息的支撑。您
  • 只能够经过主线程或许主队列中进行对UIKit中的类的运用(但凡由UIResponder派生的类在没有任何相关阐明时都适用)
  • UIKit 能够 与 SwiftUI无缝协作

承继架构图

首要 引入 一张 承继架构图:

02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】
咱们从这张承继架构图,能够看到,UIKit中的一切类都承继自OC中的基类NSObject(Swift中尽管重写了UIKit的中心类、Foundation的中心类,这一点同样适用)

02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】
02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】

想进一步了解Cocoa结构中,UIKit结构类承继体系能够参考我的 这篇文章

1. 中心目标和中心关键

UIKit中的 中心关键中心类 咱们前面现已 了解了 UIKit结构的 责任UIKit结构 类的承继关系。 现在 咱们不难 得出 UIKit结构的中心关键:

02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】

  • 交互事情处理的根底架构。相关类:
    • UIEvent
    • UITouch
    • 用户与应用程序的交互
      • UIGestureRecognizer
    • UIResponder
    • 体系与应用程序的交互
      • AppDelegate(恪守了UIApplicationDelegate协议)
    • 其他事情输入:
  • 构建UI界面的根底架构。相关类:
    • UIScreen
    • (派生自UIResponder)
      • UIView
        • UIWindow
        • UIControl
          • UIButton
      • UIApplication
      • UIViewController

2. UIKit中常用的UI组件

依据咱们多年的项目施行经历,咱们能够把UIKit结构中常用的UI组件罗列出来,为了更直观地了解类重要程度,咱们 依照派生关系的办法罗列:

  • UIResponder
    • UIView
      • UIWindow
      • UILabel
      • UIImageView
      • UIScrollView
        • UITableView
        • UICollectionView
        • UITextView
      • UITableViewCell
      • UIStackView
      • UIControl
        • UIButton
        • UITextField
        • UISwitch
        • UISlider
        • UIDatePicker
        • UIPageControl
        • UISegmentControl
      • UIWebView(现已有更优异的WKWebView替代)
      • WKWebView
      • UITabBar
      • UINavigationBar
      • UIToolBar
      • UIAlertView
      • UIActionSheet
      • UIProgressView
      • UIPickerView
      • UISearchBar
      • UIActivityIndicatorView
    • UIViewController
      • UITabBarController
      • UINavigationController
        • UIImagePickerController
        • UIVideoEditorController
      • UISplitViewController(iPad开发)
      • UISearchController

二、事情交互|UITouch

1. UITouch简介

UITouch 类是用于记载触控事情的目标

  • 每逢用户在屏幕上接触时,体系就会生成一个 UITouch 目标来表明这次接触事情的相关信息
  • 记载的事情信息包含屏幕上产生的接触的:方位size尺寸时刻阶段移动力度

2. UITouch的创立与毁掉

  • 当用户用一根手指接触屏幕时,会创立一个与手指相关联的UITouch目标,一根手指对应一个UITouch目标。
  • 当手指移动时,体系会更新同一个UITouch目标,使之能够一直保存该手指在的接触方位。
  • 当手指离开屏幕时,体系会毁掉相应的UITouch目标

3. UITouch记载触控事情的常用特点

接触产生时所在的窗口
@property(nonatomic,readonly,retain) UIWindow    *window;
接触产生时所在的视图
@property(nonatomic,readonly,retain) UIView      *view;
短时刻内点按屏幕的次数,能够依据tapCount判别单击、双击或更多的点击
@property(nonatomic,readonly) NSUInteger          tapCount;
记载了接触事情产生或变化时的时刻,单位是秒
@property(nonatomic,readonly) NSTimeInterval      timestamp;
当时接触事情所在的状况,包含`began`、`moved`、`stationary`、`ended` 和 `cancelled`
@property(nonatomic,readonly) UITouchPhase        phase;
typedef NS_ENUM(NSInteger, UITouchPhase) {
  UITouchPhaseBegan,       // 表明接触事情刚开端,手指刚接触到屏幕的时刻。whenever a finger touches the surface. 
  UITouchPhaseMoved,       // 表明手指在屏幕上移动时的阶段,即接触事情的方位产生了变化 whenever a finger moves on the surface.
  UITouchPhaseStationary,    // 表明接触事情的方位在屏幕上坚持不变,手指未产生移动 whenever a finger is touching the surface but hasn't moved since the previous event.
  UITouchPhaseEnded,       // 表明接触事情完毕,手指从屏幕上抬起的时刻whenever a finger leaves the surface.
  UITouchPhaseCancelled,     // 表明接触事情被吊销,一般是由于体系中止了接触事情的处理,例如突然来电、体系正告等状况 whenever a touch doesn't end but we need to stop tracking (e.g. putting device to face)
  UITouchPhaseRegionEntered  API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos), // whenever a touch is entering the region of a user interface
  UITouchPhaseRegionMoved   API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos), // when a touch is inside the region of a user interface, but hasn’t yet made contact or left the region
  UITouchPhaseRegionExited  API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos), // when a touch is exiting the region of a user interface
};

4. UITouch|获取触控方位的常用办法

- (CGPoint)locationInView:(UIView *)view;
//回来值表明接触在view上的方位
//这儿回来的方位是针对view的坐标系的(以view的左上角为原点(0, 0))
//调用时传入的view参数为nil的话,回来的是接触点在UIWindow的方位
- (CGPoint)previousLocationInView:(UIView *)view;
//记载了前一个接触点的方位

三、事情交互|UIEvent

1. UIEvent简介

UIEvent: 是事情目标,用于记载事情产生的时刻事情类型 每产生一个事情,就会产生一个UIEvent目标

2. UIEvent事情类型介绍

应用程序能够接纳许多不同类型的事情,包含接触事情运动事情长途操控事情按压事情

  • 接触事情是最常见的,而且被传递到开端产生接触的视图。
  • 运动事情由 UIKit 触发,而且与 Core Motion 结构报告的运动事情分隔。
  • 长途操控事情答应呼应者目标接纳来自外部配件或耳机的指令,以便它能够办理音频和视频。例如:
    • 播映视频或跳到下一个音轨
    • 按下事情表明与游戏操控器、Apple TV 遥控器或其他具有物理按钮的设备的交互。type您能够运用和特点确认事情的类型subtype

  1. 接触事情(Touch Events)
    • UIEventSubtype.touches: 表明接触事情的子类型。它包含以下几种:
      • UIEventSubtype.touchesBegan: 表明接触事情开端
      • UIEventSubtype.touchesMoved: 表明接触事情移动
      • UIEventSubtype.touchesEnded: 表明接触事情完毕
      • UIEventSubtype.touchesCancelled: 表明接触事情被吊销
  2. 摇晃事情(Motion Events)
    • UIEventSubtype.motionShake: 表明设备摇晃事情。
  3. 长途操控事情(Remote Control Events)
    • UIEventSubtype.remoteControlPlay: 表明长途操控播映事情。
    • UIEventSubtype.remoteControlPause: 表明长途操控暂停事情。
    • UIEventSubtype.remoteControlStop: 表明长途操控中止事情。
    • UIEventSubtype.remoteControlTogglePlayPause: 表明长途操控切换播映/暂停事情。
    • UIEventSubtype.remoteControlNextTrack: 表明长途操控下一曲事情。
    • UIEventSubtype.remoteControlPreviousTrack: 表明长途操控上一曲事情。
    • UIEventSubtype.remoteControlBeginSeekingBackward: 表明长途操控开端撤退事情。
    • UIEventSubtype.remoteControlEndSeekingBackward: 表明长途操控完毕撤退事情。
    • UIEventSubtype.remoteControlBeginSeekingForward: 表明长途操控开端快进事情。
    • UIEventSubtype.remoteControlEndSeekingForward: 表明长途操控完毕快进事情。
  4. 按键事情(Press Events)
    • UIEventSubtype.presses: 表明按键事情的子类型。它包含以下几种:
      • UIEventSubtype.pressesBegan: 表明按键事情开端
      • UIEventSubtype.pressesChanged: 表明按键事情产生变化
      • UIEventSubtype.pressesEnded: 表明按键事情完毕
      • UIEventSubtype.pressesCancelled: 表明按键事情被吊销

3. UIEvent记载事情信息的常用特点

//事情类型
@property(nonatomic,readonly) UIEventType     type;
@property(nonatomic,readonly) UIEventSubtype  subtype;
//事情产生的时刻
@property(nonatomic,readonly) NSTimeInterval  timestamp;

4. UIEvent|不同事情类型的回调办法

各类型事情的回调办法都在UIResponder中

4.1 触控事情

// Generally, all responders which do custom touch handling should override all four of these methods.
// Your responder will receive either touchesEnded:withEvent: or touchesCancelled:withEvent: for each
// touch it is handling (those touches it received in touchesBegan:withEvent:).
// *** You must handle cancelled touches to ensure correct behavior in your application. Failure to
// do so is very likely to lead to incorrect behavior or crashes.
//接触开端
- (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;
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches API_AVAILABLE(ios(9.1));

单点触控多点触控

  • 4个接触事情处理办法中,都有 NSSet<*touches>UIEvent *event 两个参数
  • 一次完整的接触进程中,只会产生一个事情目标,4个接触办法都是同一个event参数
  • 假如两根手指一起接触一个view,那么view只会调用一次touchesBegan:withEvent:办法,touches参数中装着2个UITouch目标
  • 假如这两根手指一前一后分隔接触同一个view,那么view会别离调用2次touchesBegan:withEvent:办法,而且每次调用时的touches参数中只包含一个UITouch目标
  • 所以依据touches中UITouch的个数能够判别出是单点接触还是多点接触

4.2 按键事情

// Generally, all responders which do custom press handling should override all four of these methods.
// Your responder will receive either pressesEnded:withEvent or pressesCancelled:withEvent: for each
// press it is handling (those presses it received in pressesBegan:withEvent:).
// pressesChanged:withEvent: will be invoked for presses that provide an analog value
// (like thumbsticks or analog push buttons)
// *** You must handle cancelled presses to ensure correct behavior in your application. Failure to
// do so is very likely to lead to incorrect behavior or crashes.
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event API_AVAILABLE(ios(9.0));
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event API_AVAILABLE(ios(9.0));
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event API_AVAILABLE(ios(9.0));
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event API_AVAILABLE(ios(9.0));

4.3 摇晃事情

- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event API_AVAILABLE(ios(3.0));
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event API_AVAILABLE(ios(3.0));
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event API_AVAILABLE(ios(3.0));

4.4 长途操控事情

- (void)remoteControlReceivedWithEvent:(nullable UIEvent *)event API_AVAILABLE(ios(4.0));

四、事情交互|UIGestureRecognizer

1. UIGestureRecognier简介

  • iOS 3.2之后,苹果推出了手势辨认功用(Gesture Recognizer),在接触事情处理方面,大大简化了开发者的开发难度。
  • 运用UIGestureRecognizer,能轻松辨认用户在某个view上面做的一些常见手势。
  • UIGestureRecognizer是一个笼统类,对iOS中的事情传递机制面向应用进行封装,将手势音讯的传递笼统为了目标。
  • 其间界说了一切手势的基本行为,运用它的子类才干处理具体的手势。

2. 手势的笼统类——UIGestureRecognizer

UIGestureRecognizer将一些和手势操作相关的办法笼统了出来,但它本身并不完结什么手势,因而,在开发中,咱们一般不会直接运用UIGestureRecognizer的目标,而是经过其子类进行实例化,iOS体系给咱们供给了许多用于实例的子类,这些咱们后边再说,咱们先来看一下,UIGestureRecognizer中笼统出了哪些办法。

2.1 初始化办法

UIGestureRecognizer类为其子类准备好了一个一致的初始化办法,无论什么样的手势动作,其履行的成果都是相同的:

  • 初始化
    触发一个办法,能够运用下面的办法进行一致的初始化:

    - (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action
    
  • 当然,假如咱们运用alloc-init的办法,也是能够的,下面的办法能够为手势增加触发的selector:

    - (void)addTarget:(id)target action:(SEL)action;
    
  • 手势移除
    与之相对应的,咱们也能够将一个selector从其手势目标上移除:

    - (void)removeTarget:(nullable id)target action:(nullable SEL)action;
    
  • 一个手势,多个触发办法
    由于addTarget办法的存在,iOS体系答应一个手势目标能够增加多个selector触发办法,而且触发的时分,一切增加的selector都会被履行,咱们以点击手势示例如下:

    - (void)viewDidLoad {
        [super viewDidLoad];
        UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap1:)];
        [tap1 addTarget:self action:@selector(tap2:)];
        [self.view addGestureRecognizer:tap1];
    }
    -(void)tap1:(UITapGestureRecognizer *)tap
    {
        NSLog(@"%s",__func__);
    }
    -(void)tap2:(UITapGestureRecognizer *)tap
    {
        NSLog(@"%s",__func__);
    }
    

点击屏幕,打印内容如下,阐明两个办法都触发了

02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】

2.2 手势状况

UIGestureRecognizer类中有如下一个特点,里边枚举了一些手势的当时状况:

@property(nonatomic,readonly) UIGestureRecognizerState state;

枚举值如下:

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
    UIGestureRecognizerStatePossible,   // 默许的状况,这个时分的手势并没有具体的情形状况
    UIGestureRecognizerStateBegan,      // 手势开端被辨认的状况
    UIGestureRecognizerStateChanged,    // 手势辨认产生改变的状况
    UIGestureRecognizerStateEnded,      // 手势辨认完毕,将会履行触发的办法
    UIGestureRecognizerStateCancelled,  // 手势辨认吊销
    UIGestureRecognizerStateFailed,     // 辨认失利,办法将不会被调用
    UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded 
};

2.3 常用特点和办法

//手势署理 署理中有一些手势触发的办法,后边拿出来具体阐明
@property(nullable,nonatomic,weak) id <UIGestureRecognizerDelegate> delegate; 
//设置手势是否有用
@property(nonatomic, getter=isEnabled) BOOL enabled;  
//获取手势所在的View
@property(nullable, nonatomic,readonly) UIView *view;          
//默许是YES。当辨认到手势的时分,中止touchesCancelled:withEvent:或pressesCancelled:withEvent:发送的一切接触事情。
@property(nonatomic) BOOL cancelsTouchesInView;     
//默许为NO ,在接触开端的时分,就会发音讯给事情传递链,假如设置为YES,在接触没有被辨认失利前,都不会给事情传递链发送音讯。  
@property(nonatomic) BOOL delaysTouchesBegan;    
//默许为YES 。这个特点设置手势辨认完毕后,是马上发送touchesEnded或pressesEnded音讯到事情传递链或许等候一个很短的时刻后,假如没有接纳到新的手势辨认使命,再发送。
@property(nonatomic) BOOL delaysTouchesEnded;         
@property(nonatomic, copy) NSArray<NSNumber *> *allowedTouchTypes NS_AVAILABLE_IOS(9_0); // Array of UITouchType's as NSNumbers.
@property(nonatomic, copy) NSArray<NSNumber *> *allowedPressTypes NS_AVAILABLE_IOS(9_0); // Array of UIPressTypes as NSNumbers.
//[A requireGestureRecognizerToFail:B]手势互斥 它能够指定当A手势产生时,即使A现已滿足条件了,也不会马上触发,会比及指定的手势B确认失利之后才触发。
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
//获取当时接触的点
- (CGPoint)locationInView:(nullable UIView*)view;
//设置接触点数
- (NSUInteger)numberOfTouches;
//获取某一个接触点的接触方位
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view; 

2.3.1 单个特点详解

其间几个BOOL值的特点,对于手势触发的操控也十分重要:

@property(nonatomic) BOOL cancelsTouchesInView;
@property(nonatomic) BOOL delaysTouchesBegan;
@property(nonatomic) BOOL delaysTouchesEnded;
- (void)viewDidLoad {
    [super viewDidLoad];
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    pan.cancelsTouchesInView = NO;
//    pan.delaysTouchesBegan = YES;
    [self.view addGestureRecognizer:pan];    
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchMoved手势触发");
}
-(void)pan:(UIPanGestureRecognizer *)pan{
    NSLog(@"pan手势触发");
}

pan.cancelsTouchesInView特点默许设置为YES

  • 假如辨认到了手势,体系将会发送touchesCancelled:withEvent:音讯在其时刻传递链上,中止接触事情的传递
  • 也便是说默许当辨认到手势时,touch事情传递的办法将被中止而不履行,假如设置为NO,touch事情传递的办法依然会被履行
  • 上例中咱们运用了Pan手势touchesMoved两个触发办法
  • 当咱们把cancelTouchesInView设置为NO时,在屏幕上滑动,两种办法都在触发,打印如下:
    02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】
  • 而当咱们将pan.cancelsTouchesInView = YES特点设置为YES时,打印成果如下
    02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】
    • 咱们发现touchesMoved的办法依然被调用了,这是为什么呢?
    • 这就涉及到第二个特点delaysTouchesBegan
      • 这是由于手势辨认是有一个进程的,拖拽手势需求一个很小的手指移动的进程才干被辨以为拖拽手势
      • 而在一个手势触发之前,是会一起发音讯给事情传递链的,所以才会有最开端的几个touchMoved办法被调用,当辨认出拖拽手势今后,就会中止touch事情的传递。
      • delaysTouchesBgan特点用于操控这个音讯的传递机遇,默许这个特点为NO,此刻在接触开端的时分,就会发音讯给事情传递链
      • 假如咱们设置为YES,在接触没有被辨认失利前,都不会给事情传递链发送音讯。
        因而当咱们设置pan.delaysTouchesBegan = YES;时打印内容如下
        02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】
      • 由于此刻在拖拽手势辨认失利之前,都不会给时刻传递链发送音讯,所以就不会在调用touchesMoved触发事情了
      • delaysTouchesEnded特点默许是YES,当设为YES时在手势辨认完毕后,会等候一个很短的时刻,假如没有接纳到新的手势辨认使命,才会发送touchesEnded音讯到事情传递链,设置为NO之后会马上发送touchesEnded音讯到事情传递链咱们同样来看一个例子:
    - (void)viewDidLoad {
        [super viewDidLoad];
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
        tap.numberOfTapsRequired = 3;
    // tap.cancelsTouchesInView = NO;
    // tap.delaysTouchesBegan = YES;
        tap.delaysTouchesEnded = NO;
        [self.view addGestureRecognizer:tap];    
    }
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        NSLog(@"touchBegan手势开端");
    }
    -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"touchEnd手势触发完毕");
    }
    -(void)tap:(UITapGestureRecognizer *)tap
    {
        NSLog(@"tap手势触发");
    }
    
  • tap.delaysTouchesEnded = NO;时,轻拍三下屏幕,打印如下
    02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】
  • 咱们发现咱们每点击一下,都会当即发送touchesEnded音讯到事情传递链。
    而当tap.delaysTouchesEnded = YES;时,轻拍三下屏幕,打印如下
    02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】
  • 等三下轻拍手势辨认完毕后,才会发送音讯到事情传递链。

2.3.2 关键办法详解-手势间的互斥处理

  • 同一个View上是能够增加多个手势目标的,默许这些手势是互斥的。一个手势触发了就会默许屏蔽其他相似的手势动作
  • 比方:
    • 单击和双击并存时,假如不做处理,它就只能发送出单击的音讯。
    • 为了能够辨认出双击手势,就需求用下面的办法一个特别处理逻辑,即先判别手势是否是双击,在双击失效的状况下作为单击手势处理。
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;

**[A requireGestureRecognizerToFail:B] **

  • 它能够指定当A手势产生时,即使 A现已满足条件了,也不会马上触发
  • 比及指定的手势B确认失利之后A才触发。 例子:
- (void)viewDidLoad {
    [super viewDidLoad];
    UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap1:)];
    tap1.numberOfTapsRequired = 1;
    [self.view addGestureRecognizer:tap1];
    UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap2:)];
    tap2.numberOfTapsRequired = 2;
    [self.view addGestureRecognizer:tap2];  
   //当tap2手势触发失利时才会触发tap1手势
    [tap1 requireGestureRecognizerToFail:tap2];
}
-(void)tap1:(UITapGestureRecognizer *)tap
{
    NSLog(@"tap1手势触发");
}
-(void)tap2:(UITapGestureRecognizer *)tap
{
    NSLog(@"tap2手势触发");
}

2.3.3 UIGestureRecognizerDelegate

前面咱们说到过关于手势目标的协议署理,经过署理的回调,咱们能够进行自界说手势,也能够处理一些复杂的手势关系,其间办法如下:

//手指接触屏暗地回调的办法,回来NO则不再进行手势辨认,办法触发等
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
//开端进行手势辨认时调用的办法,回来NO则完毕,不再触发手势
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
//是否支撑多时分触发,回来YES,则能够多个手势一同触发办法,回来NO则为互斥
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
//下面这个两个办法也是用来操控手势的互斥履行的
//这个办法回来YES,榜首个手势和第二个互斥时,榜首个会失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);
//这个办法回来YES,榜首个和第二个互斥时,第二个会失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);

3. UIGestureRecognizer子类及子类特点

除了UIGestureRecognizer中的办法和特点是一切子类通用的之外,UIGestureRecognizer子类中别离有不同的特点和办法来对应不同的手势。


UIGestureRecognizer的子类:

3.1 UITapGestureRecognizer|点击手势

点击手势十分简略,支撑单击和多次点击,在咱们手指接触屏幕并抬起手指时会进行触发,其间有如下两个特点咱们能够进行设置:

//设置点击次数,默许为单击
@property (nonatomic) NSUInteger  numberOfTapsRequired; 
//设置一起点击的手指数
@property (nonatomic) NSUInteger  numberOfTouchesRequired;

3.2 UIPinchGestureRecognizer|捏合手势

捏合手势是当咱们双指捏合和扩张会触发动作的手势,咱们能够设置的特点如下:

//设置缩放比例
@property (nonatomic)          CGFloat scale; 
//设置捏合速度
@property (nonatomic,readonly) CGFloat velocity;

3.3 UIPanGestureRecognzer|拖拽手势

当咱们点中视图进行慢速拖拽时会触发拖拽手势的办法。

//设置触发拖拽的最少接触点,默许为1
@property (nonatomic)          NSUInteger minimumNumberOfTouches; 
//设置触发拖拽的最多接触点
@property (nonatomic)          NSUInteger maximumNumberOfTouches;  
//获取当时方位
- (CGPoint)translationInView:(nullable UIView *)view;            
//设置当时方位
- (void)setTranslation:(CGPoint)translation inView:(nullable UIView *)view;
//设置拖拽速度
- (CGPoint)velocityInView:(nullable UIView *)view;

3.4 UISwipeGestureRecognizer|滑动手势

滑动手势和拖拽手势的不同之处在于滑动手势更快,而拖拽比较慢。

//设置触发滑动手势的接触点数
@property(nonatomic) NSUInteger                        numberOfTouchesRequired; 
//设置滑动方向
@property(nonatomic) UISwipeGestureRecognizerDirection direction;  
//枚举如下
typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) {
    UISwipeGestureRecognizerDirectionRight = 1 << 0,
    UISwipeGestureRecognizerDirectionLeft  = 1 << 1,
    UISwipeGestureRecognizerDirectionUp    = 1 << 2,
    UISwipeGestureRecognizerDirectionDown  = 1 << 3
};

3.5 UIRotationGestureRecognizer|旋转手势

进行旋转动作时触发手势办法。

//设置旋转角度
@property (nonatomic)          CGFloat rotation;
//设置旋转速度 
@property (nonatomic,readonly) CGFloat velocity;

3.6 UILongPressGestureRecognizer|长按手势

进行长按的时分触发的手势办法。

//设置触发前的点击次数
@property (nonatomic) NSUInteger numberOfTapsRequired;    
//设置触发的接触点数
@property (nonatomic) NSUInteger numberOfTouchesRequired; 
//设置最短的长按时刻
@property (nonatomic) CFTimeInterval minimumPressDuration; 
//设置在按触时时答应移动的最大距离 默许为10像素
@property (nonatomic) CGFloat allowableMovement;

3.7 自界说手势

  • 在.m文件中需求引入#import <UIKit/UIGestureRecognizerSubclass.h>。
  • 自界说手势承继:UIGestureRecognizer
  • 完结下面的办法,在以下办法中判别自界说手势是否完结:
– touchesBegan:withEvent:
– touchesMoved:withEvent:  
– touchesEnded:withEvent:  
- touchesCancelled:withEvent: 

五、事情交互|UIResponder

1. UIResponder简介

  • UIResponder是iOS中一切呼应者目标的基类,包含视图View视图操控器ViewController应用程序目标Application等。
  • UIResponder负责呼应并处理来自用户的接触事情按压事情加快事情长途操控事情键盘事情其他事情

2. UIResponderStandardEditActions协议介绍

UIResponder恪守了UIResponderStandardEditActions协议,且内部对办法进行了完结

#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

3. UIResponder 常用特点介绍

#pragma mark - 呼应者相关办法
/** 获取下一个呼应者 */
@property(nonatomic, readonly, nullable) UIResponder *nextResponder;
/** 是否答应成为榜首呼应者。默许回来NO */
@property(nonatomic, readonly) BOOL canBecomeFirstResponder;
/** 设置成为榜首呼应者 */
- (BOOL)becomeFirstResponder;
/** 是否答应抛弃榜首呼应者。默许回来YES */
@property(nonatomic, readonly) BOOL canResignFirstResponder;
/** 设置抛弃榜首呼应者 */
- (BOOL)resignFirstResponder;
/** 判别目标是否是榜首呼应者 */
@property(nonatomic, readonly) BOOL isFirstResponder;

4. UIResponder|接触事情相关回调办法

#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);

5. UIResponder|按压事情相关回调办法

#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);

6. UIResponder|加快事情相关回调办法

#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);

7. UIResponder|长途操控事情相关回调办法

/** 长途操控事情 */
- (void)remoteControlReceivedWithEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(4_0);

8. UIResponder|其它办法

//
// UIResponder.h
// UIKit
//
// Copyright (c) 2005-2018 Apple Inc. All rights reserved.
//
//  详解 UIResponder.h
//  Version iOS 10.3
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKitDefines.h>
#import <UIKit/UIEvent.h>
#import <UIKit/UIKeyCommand.h>
#import <UIKit/UIPasteConfigurationSupporting.h>
#import <UIKit/UIUserActivity.h>
NS_HEADER_AUDIT_BEGIN(nullability, sendability) 
@class UIPress;
@class UIPressesEvent;
#pragma mark - UIResponder类界说
NS_CLASS_AVAILABLE_IOS(2_0) NS_SWIFT_UI_ACTOR
@interface UIResponder : NSObject <UIResponderStandardEditActions>
 ...
/** 回来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

9. UIResponder运用Demo

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获取下一个呼应者,呼应者顺序为:

02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】

2. 设置与吊销榜首呼应者

//
//  FirstResponderView.m
//  ResponderDemo
//
//  Created by VanZhang on 2017/5/12.
//  Copyright  2017年 . All rights reserved.
//
#import "FirstResponderView.h"
@implementation FirstResponderView
/** 演示设置为榜首呼应者 */
- (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。 设置为榜首呼应者后,目标则能够承受长途操控事情进行处理(如耳机线控)。 UITextFieldUITextView成为榜首呼应者后会弹出输入键盘,吊销榜首呼应者则会躲藏输入键盘。

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. 长途操控办法,一般用于耳机线控


//
//  AudioView.m
//  ResponderDemo
//
//  Created by VanZhang on 2017/5/12.
//  Copyright  2017年 . All rights reserved.
//
#import "AudioView.h"
#import <AVFoundation/AVFoundation.h>
@implementation AudioView
- (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)设置成为榜首呼应者(UIViewControllerAppDelegate中不需求设置)
    // 设置成为榜首呼应者
    [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中完结长按菜单(仿制、张贴等)

//
//  MenuLabel.m
//  ResponderDemo
//
//
#import "MenuLabel.h"
@implementation MenuLabel
- (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)在显现菜单之前设置目标成为榜首呼应者(UIViewControllerAppDelegate中不需求设置)
    /** 答应目标成为榜首呼应者 */
    - (BOOL)canBecomeFirstResponder {
        return YES;
    }
    // 设置成为榜首呼应者
    [self becomeFirstResponder];
    

-(3)回来菜单需求显现的按钮,偏重写完结对应办法 “`objc

/** 回来需求显现的菜单按钮 */
- (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完结画板吊销/重做功用

/** ==============DrawingBoardView.h文件=================== */
#import <UIKit/UIKit.h>
/** 画板View */
@interface DrawingBoardView : UIView
@end
/** 划线Model */
@interface LineModel : NSObject
@property (nonatomic) CGPoint begin;
@property (nonatomic) CGPoint end;
@end
/** ==============DrawingBoardView.m文件=================== */
#import "DrawingBoardView.h"
/** 画板View */
@interface DrawingBoardView ()
@property (nonatomic, strong) LineModel *currentLine;
@property (nonatomic, strong) NSMutableArray<LineModel *> *toucheArray;
@end
@implementation DrawingBoardView
- (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 (LineModel *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 = [[LineModel 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 = [[LineModel alloc] init];
        _currentLine.begin = locTouch;
        _currentLine.end = locTouch;
    }
}
/** 划线完毕 */
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 完毕符号吊销分组
    [self.undoManager endUndoGrouping];
}
/** 增加划线 */
- (void)addLine:(LineModel *)line
{
    // 增加划线偏重绘画板
    [self.toucheArray addObject:line];
    [self setNeedsDisplay];
    // 注册吊销办法
    [[self.undoManager prepareWithInvocationTarget:self] removeLine:line];
}
/** 移除划线 */
- (void)removeLine:(LineModel *)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、自界说方便键

//
//  KeyCommandView.m
//  ResponderDemo
//
//  Created by VanZhang on 2017/5/17.
//  Copyright  2017年 . All rights reserved.
//
#import "KeyCommandView.h"
@implementation KeyCommandView
- (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输入键盘

//
//  CustomInputView.m
//  ResponderDemo
//
//  Created by VanZhang on 2017/5/18.
//  Copyright  2017年 . All rights reserved.
//
#import "CustomInputView.h"
#define MAIN_SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width   //!< 屏幕的Width
@interface CustomInputView ()
@property (nonatomic, strong) UITextField *textField;
@property (nonatomic, strong) UIView *customInputView;
@property (nonatomic, strong) UIToolbar *customAccessoryView;
@end
@implementation CustomInputView
- (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 

六、UIApplication

UIApplication 是iOS应用程序的中心类之一,承担着办理应用程序生命周期事情处理应用程序等级操作的重要角色,为应用程序的正常运转和用户体验供给了根底支撑。

以下是UIApplication的简介:

  • UIApplication目标是应用程序的标志
  • 运用UIApplication目标能进行一些应用等级的操作
  • 每一个应用程序都有自己的榜首个UI目标便是UIApplication目标。
  • 经过UIApplication *app = [UIApplication sharedApplication];能够取得这个单例目标。

1. UIApplication目标的创立机遇

那么UIApplication目标是什么时分被创立的呢?
咱们找到程序的入口main.m 阅读 main 函数

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

咱们发现程序一开端调用了UIApplicationMain办法,而且还有4个参数:

  • argc

    The count of arguments in argv; this usually is the corresponding parameter to main.

  • argv

    A variable list of arguments; this usually is the corresponding parameter to main.

  • principalClassName

    The name of the UIApplication class or subclass. If you specify nil, UIApplication is assumed.

  • delegateClassName

    The name of the class from which the application delegate is instantiated. If principalClassName designates a subclass of UIApplication, you may designate the subclass as the delegate; the subclass instance receives the application-delegate messages. Specify nil if you load the delegate object from your application’s main nib file.


  • argc:体系或许用户传入的参数
  • argv:体系或用户传入的实践参数 关键放在第三、四个参数
  • 第三个参数 nil:代表UIApplication类名或许子类名称,nil 相当于 @"UIApplicaiton";
  • 第四个参数:代表UIApplicaiton的署理名称 NSStringFromClass([AppDelegate class] 相当于 @"AppDelegate";

2. 了解应用程序发动的进程

此刻咱们能够依据UIApplicationMain函数了解程序发动的进程:

依据传递的类名创立UIApplication目标,这是榜首个目标 2. 创立UIApplication署理目标,并给UIApplicaiton目标设置署理

  1. 开启主线程运转循环 main events loop处理事情,坚持程序一直运转
  2. 加载info.plist,判别是否指定mian(xib 或许 storyboard)假如指定就去加载

3. AppDelegate回调办法

在创立UIApplication署理目标,并给UIApplicaiton目标设置署理AppDelegate之后,UIApplication应用级事情的办理就经过恪守了UIApplicationDelegate协议的署理目标AppDelegate的回调来分发出去。

因而,咱们应该对 UIApplicationDelegate协议 中的常用回调办法有所了解:

AppDelegate的回调办法:

3.1 App初始化:

application(_:willFinishLaunchingWithOptions:): * 当应用程序行将完结发动进程时调用,但在应用程序界面显现之前。 * 能够在此办法中进行应用程序的初始化设置和准备工作。 2. application(_:didFinishLaunchingWithOptions:): * 当应用程序完结发动过程时调用,此刻应用程序现已准备好显现界面。 * 能够在此办法中进行应用程序的终究设置和准备工作。

对应的告诉的名称:

3.2 应用程序生命周期办理:

UIApplication 负责办理应用程序的生命周期,包含应用程序的发动运转进入后台康复等阶段:

applicationDidBecomeActive(_:): * 当应用程序从后台切换到前台并变为活动状况时调用。 * 能够在此办法中康复应用程序的运转状况和处理需求当即履行的使命。 2. applicationWillResignActive(_:): * 当应用程序行将从活动状况切换到非活动状况时调用,如来电、弹出体系正告等状况。 * 能够在此办法中暂停应用程序的运转状况和处理需求延迟履行的使命。 3. applicationDidEnterBackground(_:): * 当应用程序进入后台运转时调用,一般在此办法中保存应用程序的状况和数据。 * 能够在此办法中履行一些后台使命和整理操作。 4. applicationWillEnterForeground(_:): * 当应用程序行将从后台切换到前台时调用,一般在此办法中康复应用程序的状况和数据。 * 能够在此办法中履行一些前台准备工作和更新界面操作。 5. applicationWillTerminate(_:): * 当应用程序行将中止时调用,一般在此办法中保存应用程序的终究状况和数据。 * 能够在此办法中履行一些整理操作和开释资源。

对应的告诉的名称:

3.3 长途告诉事情:

3.4 方便操作QuickAction和用户活动UserActivity:

3.5 WatchKit交互

3.6 HealthKit交互

3.7 Opening a URL-specified resource

3.8 SiriKit事情处理

3.9 CloudKit事情处理

3.10 内存正告等体系环境变化回调

4. 应用级事情处理

官方介绍UIApplication

  • 应用程序生命周期办理:
    • shared:回来单例的UIApplication目标,用于获取应用程序的全局状况。
    • delegate:设置或获取应用程序的托付目标,一般为完结UIApplicationDelegate协议的目标。
  • 应用程序状况获取:
    • applicationState:获取当时应用程序的状况,包含活动状况、后台状况和挂起状况。 应用程序操作:
    • openURL(_:options:completionHandler:):经过指定的URL翻开其他应用程序或履行其他操作。
    • canOpenURL(_:):查看是否能够经过指定的URL翻开其他应用程序。
  • 告诉注册:
    • registerForRemoteNotifications():注册接纳长途告诉。
    • unregisterForRemoteNotifications():吊销接纳长途告诉的注册。
  • 本地告诉:
    • presentLocalNotificationNow(_:):当即显现本地告诉。
    • scheduleLocalNotification(_:):守时显现本地告诉。
  • 应用程序图标角标:
    • applicationIconBadgeNumber:获取或设置应用程序图标的角标数字。 状况栏操控:
    • statusBarStyle:获取或设置状况栏的款式。
    • setStatusBarHidden(_:with:):显现或躲藏状况栏。
  • 应用程序退出:
    • terminate():退出应用程序。
  • 应用程序间跳转:
    • open(_:options:completionHandler:):经过指定的URL发动或跳转到其他应用程序。
    • open(_:options:completionHandler:):经过指定的URL发动或跳转到其他应用程序。
  • 体系声响与震动:
    • beginBackgroundTask(withName:expirationHandler:):开端后台使命,延伸应用程序在后台运转的时刻。
    • endBackgroundTask(_:):完毕后台使命。
  • 长途操控:
    • beginReceivingRemoteControlEvents():开端接纳长途操控事情。
    • endReceivingRemoteControlEvents():完毕接纳长途操控事情。
  • 应用程序状况保存和康复:
    • beginBackgroundTask(withName:expirationHandler:):开端后台使命,延伸应用程序在后台运转的时刻。
    • endBackgroundTask(_:):完毕后台使命。

5. 代码示例:

  • 设置应用程序图标右上角的红色提示数字
    @property(nonatomic) NSInteger applicationIconBadgeNumber;

        UIApplication *app = [UIApplication sharedApplication];
        app.applicationIconBadgeNumber = 10;
        // 创立告诉目标
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil];
        // 注册用户告诉
        [app registerUserNotificationSettings:setting];
    

    注:苹果为了增强用户体验,在iOS8今后咱们需求创立告诉才干完结图标右上角提示,iOS8之前直接设置applicationIconBadgeNumber的值即可。

  • 设置联网指示器的可见性
    @property(nonatomic,getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;

    app.networkActivityIndicatorVisible= YES;
    
  • 办理状况栏
    从iOS7开端,体系供给了2种办理状况栏的办法
    a.经过UIViewController办理(每一个UIViewController都能够拥有自己不同的状况栏)在iOS7中,默许状况下,状况栏都是由UIViewController办理的,UIViewController完结下列办法就能够轻松办理状况栏的可见性和款式
    状况栏的款式   - (UIStatusBarStyle)preferredStatusBarStyle;
    状况栏的可见性  -(BOOL)prefersStatusBarHidden;

    #pragma mark-设置状况栏的款式
    -(UIStatusBarStyle)preferredStatusBarStyle {
      //设置为白色
      //return UIStatusBarStyleLightContent;
      //默许为黑色
       return UIStatusBarStyleDefault;
    }
    #pragma mark-设置状况栏是否躲藏(否)
    -(BOOL)prefersStatusBarHidden {
      return NO;
    }
    

    b.经过UIApplication办理(一个应用程序的状况栏都由它一致办理)假如想运用UIApplication来办理状况栏,首要得修正Info.plist的设置,增加选中行,并将NO改为YES,这篇文章中有具体介绍iOS中用application 来办理电池栏状况
    Info.plist的设置:

    02-iOS 多媒体技能| 图形处理结构-UIKit关键回忆1【UITouch、UIEvent、手势处理、UIResponder、UIApplication等】

    //经过sharedApplication获取该程序的UIApplication目标
    UIApplication *app=[UIApplication sharedApplication];
    //设置状况栏的款式
    //app.statusBarStyle=UIStatusBarStyleDefault;//默许(黑色)
    //设置为白色+动画作用
    [app setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
    //设置状况栏是否躲藏
    app.statusBarHidden=YES;
    //设置状况栏是否躲藏+动画作用
    [app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
    

    c.总结

    假如状况栏的款式只设置一次,那就用UIApplication来进行办理,而且UIApplication能够供给动画作用;
    假如状况栏是否躲藏,款式纷歧那就用每个操控器对自己的状况栏进行办理。

  • openURL:办法
    UIApplication有个功用十分强大的openURL:办法
    - (BOOL)openURL:(NSURL*)url;
    openURL:办法的部分功用有

            UIApplication *app = [UIApplicationsharedApplication];
            打电话  [app openURL:[NSURLURLWithString:@"tel://110"]];
            发短信  [app openURL:[NSURLURLWithString:@"sms://10086"]];
            发邮件  [app openURL:[NSURLURLWithString:@"mailto://xxcc@fox.com"]];
            翻开一个网页资源 [app openURL:[NSURL URLWithString:@"http://www.baidu.com"]];
            翻开其他app程序   openURL办法,能够翻开其他APP。
    

    体系内部依据不同的头标示来做出不同的相应。

  • 判别程序运转状况

      //判别程序运转状况
      /*
       UIApplicationStateActive, 
       UIApplicationStateInactive, 
       UIApplicationStateBackground
       */
    UIApplication *app = [UIApplication sharedApplication];
    if(app.applicationState ==UIApplicationStateInactive){
          NSLog(@"程序在运转状况");
      }
    
  • 阻止屏幕变暗进入休眠状况

     //阻止屏幕变暗,慎重运用本功用,由于十分耗电。
     UIApplication *app = [UIApplication sharedApplication];
     app.idleTimerDisabled =YES;