YYKit-Example项目阅读——Animated Image

591 阅读2分钟

Animated Image

首先,致敬YYKit,虽然是几年前的库了,但当我决定要开始阅读优秀源码的时候,我第一个想到的是他。感谢ibireme。这篇是YYKit源码笔记第一篇,从Example项目中,Image的Animated Image开始。

正文

效果一

点击图片以暂停/播放

在图片上左右拖动能实现快进/倒带

效果图

实现这个效果主要是靠YYImageExampleHelper中的两个类方法。

// 添加点击手势
+ (void)addTapControlToAnimatedImageView:(YYAnimatedImageView *)view {
    if (!view) return;
    view.userInteractionEnabled = YES;
    __weak typeof(view) _view = view;
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithActionBlock:^(id sender) {
        if ([_view isAnimating]) [_view stopAnimating];
        else  [_view startAnimating];
        
        // add a "bounce" animation
        UIViewAnimationOptions op = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState;
        [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
            _view.layer.transformScale = 0.97;
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
                _view.layer.transformScale = 1.008;
            } completion:^(BOOL finished) {
                [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
                    _view.layer.transformScale = 1;
                } completion:NULL];
            }];
        }];
    }];
    [view addGestureRecognizer:tap];
}
// 添加滑动手势
+ (void)addPanControlToAnimatedImageView:(YYAnimatedImageView *)view {
    if (!view) return;
    view.userInteractionEnabled = YES;
    __weak typeof(view) _view = view;
    __block BOOL previousIsPlaying;
    
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithActionBlock:^(id sender) {
        UIImage<YYAnimatedImage> *image = (id)_view.image;
        if (![image conformsToProtocol:@protocol(YYAnimatedImage)]) return;
        UIPanGestureRecognizer *gesture = sender;
        CGPoint p = [gesture locationInView:gesture.view];
        CGFloat progress = p.x / gesture.view.width; // gif图片进度
        if (gesture.state == UIGestureRecognizerStateBegan) {
            previousIsPlaying = [_view isAnimating];
            [_view stopAnimating];
            _view.currentAnimatedImageIndex = image.animatedImageFrameCount * progress; // 记录当前gif图片的帧
        } else if (gesture.state == UIGestureRecognizerStateEnded ||
                   gesture.state == UIGestureRecognizerStateCancelled) {
            if (previousIsPlaying) [_view startAnimating];
        } else {
            _view.currentAnimatedImageIndex = image.animatedImageFrameCount * progress;
        }
    }];
    [view addGestureRecognizer:pan];    
}

效果二

星
这个效果只需要一张图片和一段代码

图

- (void)addSpriteSheetImageWithText:(NSString *)text {
    NSString *path = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"ResourceTwitter.bundle/fav02l-sheet@2x.png"];
    UIImage *sheet = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:path] scale:2];
    NSMutableArray *contentRects = [NSMutableArray new];
    NSMutableArray *durations = [NSMutableArray new];
    
    
    // 8 * 12 sprites in a single sheet image  根据大图切割成等分小图
    CGSize size = CGSizeMake(sheet.size.width / 8, sheet.size.height / 12);
    for (int j = 0; j < 12; j++) {
        for (int i = 0; i < 8; i++) {
            CGRect rect;
            rect.size = size;
            rect.origin.x = sheet.size.width / 8 * i;
            rect.origin.y = sheet.size.height / 12 * j;
            [contentRects addObject:[NSValue valueWithCGRect:rect]];
            [durations addObject:@(1 / 60.0)];
        }
    }
    // 核心
    YYSpriteSheetImage *sprite;
    sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:sheet
                                                     contentRects:contentRects
                                                   frameDurations:durations
                                                        loopCount:0];
    [self addImage:sprite size:size text:text];
}

总结

1.点击的弹性效果实现起来还是比较简单的,但是代码看起来让人极度舒适。如__weak typeof(view) _view = view;

2.原来UIImageView有startAnimating和stopAnimating的方法

3.通过_view.currentAnimatedImageIndex = image.animatedImageFrameCount * progress;可以猜测他加载gif图片是逐帧加载

4.效果二真是contentsRect的最佳实践。