Lottie 动画 官方用法 分析

#import "AnimationExplorerViewController.h"
#import "JSONExplorerViewController.h"
#import "LAQRScannerViewController.h"
#import 

typedef enum : NSUInteger {
  ViewBackgroundColorWhite,
  ViewBackgroundColorBlack,
  ViewBackgroundColorGreen,
  ViewBackgroundColorNone
} ViewBackgroundColor;

@interface AnimationExplorerViewController ()

@property (nonatomic, assign) ViewBackgroundColor currentBGColor;
@property (nonatomic, strong) UIToolbar *toolbar;
@property (nonatomic, strong) UISlider *slider;

/**
 动画承载视图
 */
@property (nonatomic, strong) LOTAnimationView *laAnimation;

@end

@implementation AnimationExplorerViewController

- (void)setCurrentBGColor:(ViewBackgroundColor)currentBGColor {
  _currentBGColor = currentBGColor;
  switch (currentBGColor) {
    case ViewBackgroundColorWhite:
      self.view.backgroundColor = [UIColor whiteColor];
      break;
    case ViewBackgroundColorBlack:
      self.view.backgroundColor = [UIColor blackColor];
      break;
    case ViewBackgroundColorGreen:
      self.view.backgroundColor = [UIColor colorWithRed:50.f/255.f
                                                  green:207.f/255.f
                                                   blue:193.f/255.f
                                                  alpha:1.f];
      break;
    case ViewBackgroundColorNone:
      self.view.backgroundColor = nil;
      break;
    default:
      break;
  }
}

- (void)viewDidLoad {
  [super viewDidLoad];
  
  self.currentBGColor = ViewBackgroundColorWhite;
  self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectZero];
  
  UIBarButtonItem *open = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self action:@selector(_open:)];
  UIBarButtonItem *flx1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    //分享转发按钮 —— (需要 调用 “URL” 的方法来助推)
  UIBarButtonItem *openWeb = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(_showURLInput)];
  UIBarButtonItem *flx2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  UIBarButtonItem *play = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay target:self action:@selector(_play:)];
  UIBarButtonItem *flx3 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  UIBarButtonItem *loop = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(_loop:)];
  UIBarButtonItem *flx4 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  UIBarButtonItem *zoom = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(_setZoom:)];
  UIBarButtonItem *flx5 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  UIBarButtonItem *bgcolor = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose target:self action:@selector(_setBGColor:)];
  UIBarButtonItem *flx6 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  UIBarButtonItem *close = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop target:self action:@selector(_close:)];
  self.toolbar.items = @[open, flx1, openWeb, flx2, loop, flx3, play, flx4, zoom, flx5, bgcolor, flx6, close];
  [self.view addSubview:self.toolbar];
  [self resetAllButtons];
  
  self.slider = [[UISlider alloc] initWithFrame:CGRectZero];
  [self.slider addTarget:self action:@selector(_sliderChanged:) forControlEvents:UIControlEventValueChanged];
  self.slider.minimumValue = 0;
  self.slider.maximumValue = 1;
  [self.view addSubview:self.slider];
}
  • 重新设置 所有按钮 的 显示效果
- (void)resetAllButtons {
  self.slider.value = 0;
  for (UIBarButtonItem *button in self.toolbar.items) {
    [self resetButton:button highlighted:NO];
  }
}
  • 设置播放按钮的 颜色 (通过bool值来判断 当前按钮的 状态并为之赋予不同的颜色)
- (void)resetButton:(UIBarButtonItem *)button highlighted:(BOOL)highlighted {
    
    //通过三目运算符来判断当前按钮的所处状态 点击“播放”后为黑色 :“其余按钮” 颜色为 “ :” 后的颜色
  button.tintColor = highlighted ? [UIColor blackColor] : [UIColor colorWithRed:50.f/255.f
                                                                        green:207.f/255.f
                                                                         blue:193.f/255.f
                                                                        alpha:1.f];
    NSLog(@"播放按钮 当前 所处 状态为 :%@",highlighted ? @"黑色" : @"绿色");
}

- (void)viewWillLayoutSubviews {
  [super viewWillLayoutSubviews];
  CGRect b = self.view.bounds;
  self.toolbar.frame = CGRectMake(0, b.size.height - 44, b.size.width, 44);
  CGSize sliderSize = [self.slider sizeThatFits:b.size];
  sliderSize.height += 12;
  self.slider.frame = CGRectMake(10, CGRectGetMinY(self.toolbar.frame) - sliderSize.height, b.size.width - 20, sliderSize.height);
  self.laAnimation.frame = CGRectMake(0, 0, b.size.width, CGRectGetMinY(self.slider.frame));
}
  • 监听到 进度条的 位置 改变时 动态赋值给当前的 进度条 以 实时改变 UI
- (void)_sliderChanged:(UISlider *)slider {
    
    
  self.laAnimation.animationProgress = slider.value;
    NSLog(@"%f",slider.value);
}


- (void)_open:(UIBarButtonItem *)button {
  [self _showJSONExplorer];
}

  • 自己定义的枚举类型方法 ——(里面是三个 不同的 视图 显示位置类型)
- (void)_setZoom:(UIBarButtonItem *)button {
  switch (self.laAnimation.contentMode) {
    case UIViewContentModeScaleAspectFit: {
      self.laAnimation.contentMode = UIViewContentModeScaleAspectFill;
      [self showMessage:@"Aspect Fill"];
    }  break;
    case UIViewContentModeScaleAspectFill:{
      self.laAnimation.contentMode = UIViewContentModeScaleToFill;
      [self showMessage:@"Scale Fill"];
    }
      break;
    case UIViewContentModeScaleToFill: {
      self.laAnimation.contentMode = UIViewContentModeScaleAspectFit;
      [self showMessage:@"Aspect Fit"];
    }
      break;
    default:
      break;
  }
}

- (void)_setBGColor:(UIBarButtonItem *)button {
  ViewBackgroundColor current = self.currentBGColor;
  current += 1;
  if (current == ViewBackgroundColorNone) {
    current = ViewBackgroundColorWhite;
  }
  self.currentBGColor = current;
}
  • 通过“URL”的方式来获取 动画 的 内容文件 并解析
- (void)_showURLInput {
  LAQRScannerViewController *qrVC = [[LAQRScannerViewController alloc] init];
    
  [qrVC setCompletionBlock:^(NSString *selectedAnimation) {
    if (selectedAnimation) {
        //调用 下面当中的 “URL” 的方法
      [self _loadAnimationFromURLString:selectedAnimation];
    }
    [self dismissViewControllerAnimated:YES completion:NULL];
  }];
    
  UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:qrVC];
    
  [self presentViewController:nav animated:YES completion:NULL];
}
  • 跳转到 列表 界面
- (void)_showJSONExplorer {
    //跳转到 列表 界面
  JSONExplorerViewController *vc = [[JSONExplorerViewController alloc] init];
    
    
    //让 该控制器“vc” 去调动 一个 block的 回传属性方法
  [vc setCompletionBlock:^(NSString *selectedAnimation) {
    if (selectedAnimation) {
        //并把 点中的 row cell的 动画名字 回传过去
      [self _loadAnimationNamed:selectedAnimation];
        NSLog(@"点中动画的名字:%@",selectedAnimation);
    }
      //执行完上边的block的方法后,自动向下弹走控制器
    [self dismissViewControllerAnimated:YES completion:NULL];
  }];
    
    //把 ”列表“ 控制器 设置为 根视图控制器
  UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:vc];
    //弹出模态ViewController(弹出控制器)
  [self presentViewController:navController animated:YES completion:NULL];
}

- (void)_loadAnimationFromURLString:(NSString *)URL {
    //跟下一个方法中的 意思 类同
  [self.laAnimation removeFromSuperview];
  self.laAnimation = nil;
  [self resetAllButtons];
  
    
    //跟下一个 方法中 不同的是 改方法中 是通过 “URL” 的路径字符串来 初始化 动画承载视图
  self.laAnimation = [[LOTAnimationView alloc] initWithContentsOfURL:[NSURL URLWithString:URL]];
  self.laAnimation.contentMode = UIViewContentModeScaleAspectFit;
  [self.view addSubview:self.laAnimation];
  [self.view setNeedsLayout];
    
}
  • 移除 “动画承载视图” 上的现有内容 并 赋值为空 (nil)
  • 不然~ 你将无法 选择 下一个 动画 展示在 视图上 ,因为 当前的 视图上已经有了 内容 并且你没有 及时 移除掉!
//上方block 中 所调用的方法
- (void)_loadAnimationNamed:(NSString *)named {
    //移除 “动画承载视图” 上的现有内容 并 赋值为空 (nil)
    //不然~ 你将无法 选择 下一个 动画 展示在 视图上 ,因为 当前的 视图上已经有了 内容 并且你没有 及时 移除掉!
  [self.laAnimation removeFromSuperview];
  self.laAnimation = nil;
    
    
    //将所有的 按钮 位置 复原 —— (尤其是 时间进度条上的button,通过复原。使其值 变为 “0”,这样滑块 自然 处于 开始的位置)
    //!!注意:如果不复原,滑块按钮 将位于 时间进度条的左右边既动画结束的位置!!
  [self resetAllButtons];
  
    
    //将上面 通过 点击某行 所传过来的 动画json文件名字 获取到 并 调用方法解析完后 满屏加载到 合适的 位置
  self.laAnimation = [LOTAnimationView animationNamed:named];
  self.laAnimation.contentMode = UIViewContentModeScaleAspectFit;
  [self.view addSubview:self.laAnimation];
    
    
    //将所需要的动画 加载到 当前视图 ——(此方法可写可不写)
  [self.view setNeedsLayout];
}

重绕方法 —— (此方法 该类中 并没有 实际调用到,所以 可写可不写。不影响操作~)

- (void)_rewind:(UIBarButtonItem *)button {
    //设置动画重载视图的 “进度”
    //实现原理是将 后期 更改的 赋值给 之前的 进度属性
  self.laAnimation.animationProgress = 0.5;
}

CADisplayLink是用于同步屏幕刷新频率的计时器,在开发中我们经常会遇到使用计时器的情况,例如图片轮播,进度条的绘制等就是比较常见的应用场景.

从runloop中移除

移除计时器有两个方法:
-- (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode 和
-- (void)invalidate.

我们来分析一下他们的异同

removeFromRunLoop: forMode:会将接收者从给定的模式中移除,这个方法会对计时器进行隐式的release.
在调用removeFromRunloop方法,需要做判断,如果当期计时器不在runloop的话,会出现野指针的crash.
出现crash的原因是runloop多次调用了release方法,进行了over-release.

-- (void)invalidate是从runloop所有模式中移除计时器,并取消计时器和target的关联关系.多次调用这个方法,不会出现crash.

         

- (void)_play:(UIBarButtonItem *)button {
    // isAnimationPlaying —— 播放动画时标志为YES 为 Bool 类型
    //当检测到 该动画为 点击 “播放” 按钮后 即将进入 (动画正在播放ing) 的状态并执行下面的语句
  if (self.laAnimation.isAnimationPlaying) {
      //当处于(动画正在播放ing)的 状态时 再次点击 “播放” 按钮时 将会 暂停 "滑块" 以及 "动画" 并将 "播放" 按钮的颜色 改变~
      
      //此刷新 按钮状态的 方法 可写可不写 并没任何影响
    [self resetButton:button highlighted:NO];
      
      
    [self.laAnimation pause];
  } else {
      //CADisplayLink是用于同步屏幕刷新频率的计时器,在开发中我们经常会遇到使用计时器的情况,例如图片轮播,进度条的绘制等就是比较常见的应用场景.

    CADisplayLink *displayLink =[CADisplayLink displayLinkWithTarget:self selector:@selector(_updateSlider)] ;
      
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
      //在此处,才是真正的 改变 “播放” 按钮的 颜色 状态
    [self resetButton:button highlighted:YES];
      
    [self.laAnimation playWithCompletion:^(BOOL animationFinished) {
        //每个计时器对象只能加入到一个runloop中,但是可以被添加到不同的模式中,当CADisplayLink被加入到runloop时,会被runloop隐式retain.如果想从所有的模式中移除计时器,需要执行-invalidate()方法.
       
      [displayLink invalidate];
        
      [self resetButton:button highlighted:NO];
    }];
  }
}

- (void)_updateSlider {
    //刷新 进度条的 变化
    //将 当前 动画 的 播放进度 赋值给 进度条的 Value 值
  self.slider.value = self.laAnimation.animationProgress;
}

- (void)_loop:(UIBarButtonItem *)button {
  self.laAnimation.loopAnimation = !self.laAnimation.loopAnimation;
    // loopAnimation :告诉动画 无限循环 —— 默认为NO
    [self resetButton:button highlighted:self.laAnimation.loopAnimation];
    
    //通过判断 按钮点击的 呈现状态(重复:不重复)
    //来展示消息提示框 (Loop Enabled循环过程中" : @"Loop Disabled终止循环播放)
  [self showMessage:self.laAnimation.loopAnimation ? @"Loop Enabled循环过程中" : @"Loop Disabled终止循环播放"];
}

- (void)_close:(UIBarButtonItem *)button {
    
  [self.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
    
}

- (void)showMessage:(NSString *)message {
  UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  messageLabel.textAlignment = NSTextAlignmentCenter;
  messageLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
  messageLabel.textColor = [UIColor whiteColor];
  messageLabel.text = message;
  
  CGSize messageSize = [messageLabel sizeThatFits:self.view.bounds.size];
  messageSize.width += 14;
  messageSize.height += 14;
  messageLabel.frame = CGRectMake(10, 30, messageSize.width, messageSize.height);
  messageLabel.alpha = 0;
  [self.view addSubview:messageLabel];
  
  [UIView animateWithDuration:0.3 animations:^{
    messageLabel.alpha = 1;
  } completion:^(BOOL finished) {
    [UIView animateWithDuration:0.3 delay:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
      messageLabel.alpha = 0;
    } completion:^(BOOL finished) {
      [messageLabel removeFromSuperview];
    }];
  }];
}


@end

你可能感兴趣的:(Lottie 动画 官方用法 分析)