在app的引导页中,经常需要动态展示加载和交互过程,本文主要是对Gif动画的调研,技术要求如下:
- 支持复杂的动态效果
- 易于维护
- 易于开发
- 兼容iOS7和小屏
- 高性能
Gif动画
优点
使用Gif动画方式展示动态效果,具有很多优点,开发维护比较简单,工作量小,只需设计师提供动画即可,相比原生制作动画效率很高。Gif还能够实现很复杂、酷炫的动画特效,甚至有些是原生无法实现的。Gif对系统版本,对屏幕尺寸没有什么要求,兼容性较好。
缺点
当然Gif也存在一些缺点,它仅支持单页动画,对于连续性的多页面动画则无能为力,比如随着引导页滑动,一个按钮将从第一页飞到第二页。它的cpu使用率也比较高,每个Gif动画增加了26%的cpu利用率(模拟器iphone 5,ios10.3)。
对于开源的引导页类库,我们以EAIntroView为例,它的实现原理实际上是在一个scrollView容器上,平铺四个imageView和一个指式条,划动时切换到上/下一个页面。当使用Gif动画时,实际上将同时播放四个gif,因此造成CPU使用率较高,真机测试iOS10.3,iphone 6,cpu使用率70%左右。
优化
由于引导页的实现方式是将多个imageView同时放到scrollView上,造成几个Gif动画同时播放,CPU使用率较高。为了解决这个问题,现引入FLAnimatedImage库。这个库支持停止、播放动画。当划到某页时,才会去播放当前页的Gif动画,这样就降低了资源消耗情况,优化后cpu利用率降低到32%。
Gif实例
写了一个Demo,基于EAIntroView,功能尚不完善,仅仅用于验证实际效果。地址:https://github.com/superzcj/ZCJGifInIntroDemo
self.gifArr = [NSMutableArray new];
NSMutableArray *views = [NSMutableArray new];
for (int i=0; i<4; i++) {
NSString *imageName = [NSString stringWithFormat:@"guideImage_%d", i + 1];
NSURL *url1 = [[NSBundle mainBundle] URLForResource:imageName withExtension:@"gif"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:data1];
FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] initWithFrame:self.view.bounds];
imageView.backgroundColor = [UIColor clearColor];
imageView.animatedImage = image;
UIView *bgView = [[UIView alloc] initWithFrame:self.view.bounds];
[bgView addSubview:imageView];
[views addObject:bgView];
[self.gifArr addObject:imageView];
}
代码如上,首先从本地读取Gif动画图片,生成FLAnimatedImage图片对象,再传递给FLAnimatedImageView以显示。为了在后面控制每个Gif对象的播放与停止,将Gif动画容器放入gifArr数组中。
EAIntroPage *page1 = [EAIntroPage pageWithCustomView:views[0]];
EAIntroPage *page2 = [EAIntroPage pageWithCustomView:views[1]];
EAIntroPage *page3 = [EAIntroPage pageWithCustomView:views[2]];
EAIntroPage *page4 = [EAIntroPage pageWithCustomView:views[3]];
EAIntroView *intro = [[EAIntroView alloc] initWithFrame:self.view.bounds andPages:@[page1,page2,page3,page4]];
[intro.skipButton setTitle:@"跳过" forState:UIControlStateNormal];
[intro setDelegate:self];
intro.tapToNext = YES;
[intro showInView:self.view animateDuration:0.3];
创建四个引导页页面,将上面生成的页面内容传递进来,最后将引导页添加到页面上。
- (void)intro:(EAIntroView *)introView pageAppeared:(EAIntroPage *)page withIndex:(NSUInteger)pageIndex {
NSLog(@"Current page index = %lu", (unsigned long)pageIndex);
for (FLAnimatedImageView *iv in self.gifArr) {
[iv stopAnimating];
}
FLAnimatedImageView *imageView = self.gifArr[pageIndex];
[imageView startAnimating];
}
滑动引导页时,停止所有的Gif动画,只播放新出现的当前页动画。
FLAnimatedImage
FLAnimatedImage是由Flipboard开源的iOS平台上播放GIF动画的一个优秀解决方案,在内存占用和播放体验都有不错的表现。它在Github上的Star有5461个,被Facebook、Dropbox等应用引用。
FLAnimatedImage的实现原理很简单,只有两个类,FLAnimatedImage负责解析GIF动画数据,读取Gif中的每一帧图片,FLAnimatedImageView则展示FLAnimatedImage处理后的动画数据,控制Gif动画的播放、停止等。
FLAnimatedImage利用CGImageSource获取图像对象、图片属性信息等,调用CGImageSourceCopyProperties方法获取到Gif动画循环次数,调用CGImageSourceCreateImageAtIndex取得帧图片,然后根据GIF图的大小和缓存策略判断需要缓存的单帧图片数量,缓存起来。
FLAnimatedImageView是UIImageView的子类,完全兼容UIImageView的各个方法。它设置GIF动画的封面帧图片,当前帧索引,GIF动画的循环播放次数,播放时间累加器,更新是否发起动画的标志位,判断是否启动GIF动画。
第三方库动态引导页
使用第三方的动态引导页类库,能大大提升开发效率。
JazzHands是一个动态引导页类库,它是基于关键帧的动画框架, 可以用于手势,滚动视图,KVO或者ReactiveCocoa, 十分方便。它在Github上star数有6102,在引导页类库中最受欢迎。
官方提供了一个很酷炫的Demo,地址:https://github.com/IFTTT/JazzHands。
总结
Gif动画 | 第三方库(JazzHands) | 动画 | |
---|---|---|---|
开发工作量 | 低 | 高 | 极高 |
维护工作量 | 低 | 高 | 极高 |
cpu利用率和内存占用 | 高(26%的cpu利用率) | 低(cpu使用率在10%) | 低 |
兼容性 | 支持iOS7,支持小屏幕 | 支持ios7,支持小屏幕 | 支持 |
适用性 | 仅支持单页动画 | 支持多种类型动画 | 无限制 |