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的最佳实践。