前言
YYImage 是一个强大的iOS图像框架,是YYKit 的组件之一。具体用法可以参考Demo。
特性:
文件结构
- YYImage : UIImage的子类,遵守 YYAnimatedImage 协议,更高级的方式来显示 Image
- YYFrameImage : 同 YYImage,能够显示帧动画,仅支持png,jpeg 格式,可以配合 YYAnimatedImageView 来播放动画
- YYSpriteSheetImage : 同 YYFrameImage, 实现另一种动画形式,可以将一张图片自定义剪裁成多张图片来播放图片动画,同样可以配合YYAnimatedImageView 使用
- YYImageCoder : 图像的编码和解码功能类,
YYImageEncoder
负责编码,YYImageDecoder
负责解码,YYImageFrame
负责管理帧图像信息,_YYImageDecoderFrame
内部私有类是其子类- YYAnimatedImageView: UIImageView 子类,用于播放图像动画,定义了 YYAnimatedImage 协议
YYAnimatedImageView
运行Demo,进入Animated Image 。有五种播放的图片动画,前三个图像格式分别是GIF,WebP,APNG,后两个分别转化成 YYFrameImage,YYSpriteSheetImage ,全部都是通过YYAnimatedImageView 播放动画的,我们进入 YYAnimatedImageView 来分析
|
|
初始化方法只是一些简单的属性设置,默认_autoPlayAnimatedImage
为YES,自动开启动画,_runloopMode
为 NSRunLoopCommonModes
,避免滑动时动画停止,因为以上的五种动画都是通过 CADisplayLink
来实现的动画, 滑动时 mode 会切换到 UITrackingRunLoopMode
导致 _link
失效,代码中实现如下 ,保证滑动时依然有效
通过设置 self.image = image;
传入 YYAnimatedImageTypeImage
type
|
|
如果当前是 YYSpriteSheetImage
会进入到 [self setContentsRect:rect forImage:newVisibleImage];
此时设置 self.layer.contentsRect = CGRectMake(0, 0, 32 / image.size.width, 32 / image.size.height);
即裁剪的第一张图像
停止动画
开始动画
自定义动画
准备工作,调用 resetAnimated
, 在 dispatch_once
中初始化 _requestQueue
, 设置maxConcurrentOperationCount
为1,串行执行请求图像任务,初始化_link
,设置target为_YYImageWeakProxy
,传入 self
赋值给 weak 属性 target,避免循环引用,添加到 mainRunLoop,mode 设置为 NSRunLoopCommonModes
开启 _link
,以大约每秒60次的频率(屏幕刷新频率)调用 step:(CADisplayLink *)link
其中 _buffer
存储图像数据, _YYAnimatedImageViewFetchOperation
用于获取图像数据 实现代码在 main
方法中的 UIImage *img = [_curImage animatedImageFrameAtIndex:idx];
|
|
主要流程:
- 确保当前图像存在,并且循环未结束
- 如果还在当前图像显示时间内,返回
- 进入下张图像显示,如存在直接显示,并更新相应属性数据,如不存在,初始化一个operation,获取下一张图像数据
_YYAnimatedImageViewFetchOperation 实现获取下张图像
_YYAnimatedImageViewFetchOperation
是 NSOperation
的子类, 用来执行获取图像操作。通过自定义main 方法实现,每添加一个 operation
, _incrBufferCount ++
, 遍历 _buffer
, 获取丢失的图像。具体获取图像通过协议方法 animatedImageFrameAtIndex:
获取
|
|
获取图像 YYImage
YYFrameImage
YYSpriteSheetImage
都实现了 YYAnimatedImage
协议方法,后两个比较简单,主要来看 YYImage
, 内部获取图像通过 _decoder
实现, 其中 preloadAllAnimatedImageFrames
属性可以用来预先加载所有图像数据
YYImageCoder
最终获取图像调用到 YYImageDecoder
内部,返回一个 YYImageFrame
实例,存储了图像信息。可以参考文章移动端图片格式调研
|
|
图像解码主要方法
根据传入的图像data 更新数据到 _frames
数组 ,里面存储的是 _YYImageDecoderFrame
。大致有三类图片数据,webP,APNG, 其他。
webP 图片通过Google的 WebP.framework 实现,APNG是 自定义实现的图像解码,其他的通过 ImageIO 框架实现的
主要看一下 _updateSourceImageIO
通过最初的图像解码得到指定Index的frame,
_YYImageDecoderFrame *frame = [(_YYImageDecoderFrame *)_frames[index] copy];
采用画布进行渲染, 最终获得图像 frame.image = image;