iOS交互、手势与动画编程|青训营笔记

275 阅读7分钟

这是我参与「第四届青训营」笔记创作活动的的第十九天。本篇文章将会简单介绍iOS的交互、手势与动画编程。

可以首先看一看对于iOS交互、手势和动画的大体关系:

image.png 引用:juejin.cn/post/712344…

一、交互与手势

手势识别器

手势识别器用来解释触摸以确定它们是否对应于特定手势,诸如滑动,捏合或旋转,如果识别他们特定的手势,他们发送动作消息到目标对象。目标对象通常是视图的控制器,它响应手势,如下图所示:

image.png

引用:www.jianshu.com/p/a8c04c702…

UIGestureRecognizer

iOS 系统提供了一些常用的手势(UIGestureRecognizer 的子类),开发者可以直接使用他们进行手势操作:

UIPanGestureRecognizer(平移或者拖动)

UIPinchGestureRecognizer(缩放)

UIRotationGestureRecognizer(旋转)

UITapGestureRecognizer(点击)

UILongPressGestureRecognizer(长按)

UISwipeGestureRecognizer(滑动)

image.png

引用:www.jianshu.com/p/a8c04c702…

手势状态

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
    UIGestureRecognizerStatePossible,   // 尚未识别是何种手势操作(但可能已经触发了触摸事件),默认状态
    UIGestureRecognizerStateBegan,      // 手势已经开始,此时已经被识别,但是这个过程中可能发生变化,手势操作尚未完成
    UIGestureRecognizerStateChanged,    // 手势状态发生转变
    UIGestureRecognizerStateEnded,      // 手势识别操作完成(此时已经松开手指)
    UIGestureRecognizerStateCancelled,  // 手势被取消,恢复到默认状态
    
    UIGestureRecognizerStateFailed,     // 手势识别失败,恢复到默认状态
    
    UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // 手势识别完成,同UIGestureRecognizerStateEnded
};

引用:juejin.cn/post/712344…

事件响应机制

UITouch介绍

typedef NS_ENUM(NSInteger, UITouchPhase) {

    UITouchPhaseBegan,             // 开始触摸
    UITouchPhaseMoved,             // 触摸移动
    UITouchPhaseStationary,       // 触摸没有移动
    UITouchPhaseEnded,             //触摸结束
    UITouchPhaseCancelled,         //取消触摸
};
@interface UITouch : NSObject

//属性
//时间戳记录了触摸事件产生或变化时的时间,单位是秒
@property(nonatomic,readonly) NSTimeInterval   timestamp;
//当前触摸事件在一个周期中所处的状态               
@property(nonatomic,readonly) UITouchPhase  phase;
 //表示短时间内点按屏幕的次数            
@property(nonatomic,readonly) NSUInteger  tapCount; 
//触摸的主半径                
@property(nonatomic,readonly) CGFloat majorRadius;
//触摸的主半径的公差
@property(nonatomic,readonly) CGFloat majorRadiusTolerance;
//触摸产生时所处的窗口。由于窗口可能发生变化,当前所在的窗口不一定是最开始的窗口
@property(nonatomic,readonly,retain) UIWindow    *window;
//触摸产生时所处的视图。由于视图可能发生变化,当前视图也不一定时最初的视图
@property(nonatomic,readonly,retain) UIView      *view;
//触摸手势数组
@property(nonatomic,readonly,copy)   NSArray   *gestureRecognizers;

//方法
//返回当前触摸点的位置
- (CGPoint)locationInView:(UIView *)view;
//返回上一个触摸点的位置
- (CGPoint)previousLocationInView:(UIView *)view;

@end

UIEvent介绍

//属性
//获取事件类型
typedef NS_ENUM(NSInteger, UIEventType) {

UIEventTypeTouches// 触摸事件
UIEventTypeMotion// 加速事件
UIEventTypeRemoteControl// 远程控制事件
UIEventTypePresses//按压事件

};

//输入事件不同类型的一些具体事件枚举
@property(nonatomic,readonly) UIEventSubtype  subtype;
UIEventSubtype 枚举:
// 不包含任何子事件类型
UIEventSubtypeNone                              = 0,
// 摇晃事件(从iOS3.0开始支持此事件)
UIEventSubtypeMotionShake                       = 1,
//远程控制子事件类型(从iOS4.0开始支持远程控制事件)
//播放事件【操作:停止状态下,按耳机线控中间按钮一下】
UIEventSubtypeRemoteControlPlay                 = 100,
//暂停事件
UIEventSubtypeRemoteControlPause                = 101,
//停止事件
UIEventSubtypeRemoteControlStop                 = 102,
//播放或暂停切换【操作:播放或暂停状态下,按耳机线控中间按钮一下】
UIEventSubtypeRemoteControlTogglePlayPause      = 103,
//下一曲【操作:按耳机线控中间按钮两下】
UIEventSubtypeRemoteControlNextTrack            = 104,
//上一曲【操作:按耳机线控中间按钮三下】
UIEventSubtypeRemoteControlPreviousTrack        = 105,
//快退开始【操作:按耳机线控中间按钮三下不要松开】
UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
//快退停止【操作:按耳机线控中间按钮三下到了快退的位置松开】
UIEventSubtypeRemoteControlEndSeekingBackward   = 107,
//快进开始【操作:按耳机线控中间按钮两下不要松开】
UIEventSubtypeRemoteControlBeginSeekingForward  = 108,
//快进停止【操作:按耳机线控中间按钮两下到了快进的位置松开】
UIEventSubtypeRemoteControlEndSeekingForward    = 109

//类
@interface UIEvent : NSObject

//属性
@property(nonatomic,readonly) UIEventType    type ;            //事件类型
@property(nonatomic,readonly) UIEventSubtype  subtype ;     //同一事件类型的具体事件
@property(nonatomic,readonly) NSTimeInterval  timestamp;    //事件触发时间间隔

//方法
//所有触摸点
- (NSSet *)allTouches; 
//窗体上的触摸点
- (NSSet *)touchesForWindow:(UIWindow *)window;
//视图上的触摸点
- (NSSet *)touchesForView:(UIView *)view;
//手势触摸点
 - (NSSet *)touchesForGestureRecognizer:(UIGestureRecognizer *)gesture;

 @end

UIResponder

//手指触碰屏幕,触摸开始
- (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;

事件派发

image.png

引用:juejin.cn/post/712344…

二、动画编程

UIView动画

UIView动画实质上是对Core Animation的封装,提供简洁的动画接口。

UIView动画可以设置的动画属性有:

  1. 大小变化(frame)
  2. 拉伸变化(bounds)
  3. 中心位置(center)
  4. 旋转(transform)
  5. 透明度(alpha)
  6. 背景颜色(backgroundColor)
  7. 拉伸内容(contentStretch)

UI类方法动画:

  1. block动画
[UIView animateWithDuration:(NSTimeInterval)  //动画持续时间
              animations:^{
              //执行的动画
 }];
[UIView animateWithDuration:(NSTimeInterval)  //动画持续时间
              animations:^{
            //执行的动画
 }                completion:^(BOOL finished) {
            //动画执行提交后的操作
 }];
[UIView animateWithDuration:(NSTimeInterval) //动画持续时间
                   delay:(NSTimeInterval) //动画延迟执行的时间
                 options:(UIViewAnimationOptions) //动画的过渡效果
              animations:^{
               //执行的动画
 }                completion:^(BOOL finished) {
               //动画执行提交后的操作
 }];
UIViewAnimationOptions的枚举值:
UIViewAnimationOptionLayoutSubviews            //进行动画时布局子控件
 UIViewAnimationOptionAllowUserInteraction      //进行动画时允许用户交互
 UIViewAnimationOptionBeginFromCurrentState     //从当前状态开始动画
 UIViewAnimationOptionRepeat                    //无限重复执行动画
 UIViewAnimationOptionAutoreverse               //执行动画回路
 UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套动画的执行时间设置
 UIViewAnimationOptionOverrideInheritedCurve    //忽略嵌套动画的曲线设置
 UIViewAnimationOptionAllowAnimatedContent      //转场:进行动画时重绘视图
 UIViewAnimationOptionShowHideTransitionViews   //转场:移除(添加和移除图层的)动画效果
 UIViewAnimationOptionOverrideInheritedOptions  //不继承父动画设置

 UIViewAnimationOptionCurveEaseInOut            //时间曲线,慢进慢出(默认值)
 UIViewAnimationOptionCurveEaseIn               //时间曲线,慢进
 UIViewAnimationOptionCurveEaseOut              //时间曲线,慢出
 UIViewAnimationOptionCurveLinear               //时间曲线,匀速

 UIViewAnimationOptionTransitionNone            //转场,不使用动画
 UIViewAnimationOptionTransitionFlipFromLeft    //转场,从左向右旋转翻页
 UIViewAnimationOptionTransitionFlipFromRight   //转场,从右向左旋转翻页
 UIViewAnimationOptionTransitionCurlUp          //转场,下往上卷曲翻页
 UIViewAnimationOptionTransitionCurlDown        //转场,从上往下卷曲翻页
 UIViewAnimationOptionTransitionCrossDissolve   //转场,交叉消失和出现
 UIViewAnimationOptionTransitionFlipFromTop     //转场,从上向下旋转翻页
 UIViewAnimationOptionTransitionFlipFromBottom  //转场,从下向上旋转翻页
  1. 弹簧(spring)动画
self.redView.alpha = 0.0;
[UIView animateWithDuration:(NSTimeInterval)//动画持续时间
                   delay:(NSTimeInterval)//动画延迟执行的时间
  usingSpringWithDamping:(CGFloat)//震动效果,范围0~1,数值越小震动效果越明显
   initialSpringVelocity:(CGFloat)//初始速度,数值越大初始速度越快
                 options:(UIViewAnimationOptions)//动画的过渡效果
              animations:^{
                 //执行的动画
                self.redView.alpha = 1.0;
        self.redView.frame = CGRectMake(200, 350, 140, 140);
 }
                  completion:^(BOOL finished) {
                 //动画执行提交后的操作
 }];
  1. 关键帧(keyframes)动画
IOS7.0后新增了关键帧动画,支持属性关键帧,不支持路径关键帧
 [UIView animateKeyframesWithDuration:(NSTimeInterval)//动画持续时间
                            delay:(NSTimeInterval)//动画延迟执行的时间
                          options:(UIViewKeyframeAnimationOptions)//动画的过渡效果
                       animations:^{
                     //执行的关键帧动画
 }
                       completion:^(BOOL finished) {
                     //动画执行提交后的操作
 }];
 UIViewAnimationOptionLayoutSubviews           //进行动画时布局子控件
UIViewAnimationOptionAllowUserInteraction     //进行动画时允许用户交互
UIViewAnimationOptionBeginFromCurrentState    //从当前状态开始动画
UIViewAnimationOptionRepeat                   //无限重复执行动画
UIViewAnimationOptionAutoreverse              //执行动画回路
UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套动画的执行时间设置
UIViewAnimationOptionOverrideInheritedOptions //不继承父动画设置

UIViewKeyframeAnimationOptionCalculationModeLinear     //运算模式 :连续
UIViewKeyframeAnimationOptionCalculationModeDiscrete   //运算模式 :离散
UIViewKeyframeAnimationOptionCalculationModePaced      //运算模式 :均匀执行
UIViewKeyframeAnimationOptionCalculationModeCubic      //运算模式 :平滑
UIViewKeyframeAnimationOptionCalculationModeCubicPaced //运算模式 :平滑均匀
//增加关键帧方法
[UIView addKeyframeWithRelativeStartTime:(double)//动画开始的时间(占总时间的比例)
                     relativeDuration:(double) //动画持续时间(占总时间的比例)
                           animations:^{
                         //执行的动画
 }];
  1. 转场动画
[UIView transitionFromView:(nonnull UIView *) toView:(nonnull UIView *) duration:(NSTimeInterval) options:(UIViewAnimationOptions) completion:^(BOOL finished) {
                 //动画执行提交后的操作
 }];

详细内容可以阅读:www.jianshu.com/p/5abc038e4…

核心动画

CAAnimation(抽象类)

继承关系: image.png

引用:juejin.cn/post/712344…

核心动画类中可以直接使用的类有:

  • CABasicAnimation 基本动画
  • CAKeyframeAnimation 关键帧动画
  • CATransition 转场动画
  • CAAnimationGroup 动画组
  • CASpringAnimation 弹簧动画

Lottie动画

Lottie动画是一种跨平台复杂动画的实现,支持iOS、android、web、react native等。通过JSON来描述动画过程。 image.png

引用:juejin.cn/post/684490…

创建lottie动画:

LOTAnimationView *lottieView = [LOTAnimationView animationNamed:@"fire"];

更多详细内容可以阅读:juejin.cn/post/684490…

Reference

《iOS 交互、手势与动画编程》juejin.cn/post/712344…

《iOS手势识别器》www.jianshu.com/p/a8c04c702…

《iOS:触摸控件UITouch、事件类UIEvent》developer.aliyun.com/article/366…

《iOS动画篇:UIView动画》www.jianshu.com/p/5abc038e4…

《iOS:核心动画的详解介绍:CAAnimation(抽象类)及其子类》developer.aliyun.com/article/366…

《Lottie - 轻松实现复杂的动画效果》juejin.cn/post/684490…