GIF 图片在 Web 时代是一种广泛使用的图片格式。 但在 iOS 中,原生库直到现在也没有提供对 GIF 比较完善的支持。 FLAnimatedImage 这个库正式专门为 iOS App 中显示 GIF 图片而来的。
FLAnimatedImage 是 Flipboard 团队开发的在它们 App 中渲染 GIF 图片使用的库。 后来 Flipboard 将 FLAnimatedImage 开源出来供大家使用。 所以你不用担心它在实践中会不会出现问题, 毕竟已经在 Flipboard 这种 App 上面经过充分的实践验证了。
因为 Flipboard App 中很多频道会展示大量的 GIF 图片,而 iOS 原生的系统库中并没有提供对 GIF 很好的支持,所以 FLAnimatedImage 就应运而生了。
大家如果在 iOS 中处理过 GIF 图片, 如果通过原生系统提供的能力, 可能只有两种方式。 并且这两种方式都不是专门针对于 GIF 的解决方案,更像是一种 hack。
第一种方式, UIImage
虽然提供了一种创建连续切换的动画图片的能力, 但这个能力更像是为了那些简单动画而服务的。 比如加载数据时候显示的 loading 图片。 如果将 GIF 图片通过这种能力来显示,会带来诸多问题。
第二种方式,可能是大家用的最多的了。 就是创建一个 UIWebView
然后在这里面把 GIF 显示出来。 但从原理上来想, UIWebView
并不是为了显示 GIF 图片而生的。 其实也算不上最佳实践。
但 iOS 原生系统库目前只提供了这几个能力, 用这些 hack 方式也是无奈之举。 关于这些问题, Flipboard 官方的技术 blog 上面有详细的说明, 感兴趣的同学可以参考这里:
http://engineering.flipboard.com/2014/05/animated-gif/
给大家介绍了基本的问题背景, 咱们就来看看 FLAnimatedImage
是如何解决这个问题的吧。 我们可以通过Carthage 将 FLAnimatedImage 集成进来, 创建这样一个 Cartfile
:
github "Flipboard/FLAnimatedImage"
然后执行:
carthage update
就可以将 FLAnimatedImage
拉取下来。 当然, 你也可以使用 Cocoapods, 如何集成请参考 FLAnimatedImage
的 Github 主页:
https://github.com/Flipboard/FLAnimatedImage
如果你使用的 Swift 可以在 Bridgeing Header 中引入 FLAnimatedImage
:
#import <FLAnimatedImage/FLAnimatedImage.h>
随后在需要的地方这样调用 FLAnimatedImage 就可以了:
//创建 FLAnimatedImageView let imageView = FLAnimatedImageView(frame: CGRect(x: 0, y: 0, width: 400, height: 400)) self.view.addSubview(imageView) let imageURLString = "https://media.giphy.com/media/Nm8ZPAGOwZUQM/giphy.gif" if let imageURL = URL(string: imageURLString) { //读取图片 let session = URLSession(configuration: URLSessionConfiguration.default) session.dataTask(with: imageURL, completionHandler: { (data, response, error) in if data != nil { let image = FLAnimatedImage(animatedGIFData: data) imageView.animatedImage = image } }).resume() }
这里给大家简单讲解一下, 首先我们初始化一个 FLAnimatedImageView
实例。 然后 URLSession 读取图片数据, 得到图片的数据 data
后, 用这个数据初始化 FLAnimatedImage
实例, 最后将它设置给 animatedImage
属性。 这样就完成了, 其余的 GIF 渲染工作都由 FLAnimatedImage
来处理。
上面的代码应该比较简明易懂,如果有疑问可以在留言中提出~
为什么说 FLAnimatedImage
相对于 iOS 原生的几种 hack 方式更趋近于最佳实践呢? 咱们简单聊聊 FLAnimatedImage
渲染 GIF 图片的原理。 FLAnimatedImage
会有两个线程同时在运转。 其中一个线程负责渲染 GIF 的每一帧的图片内容(所谓的渲染,大体上就是加载 GIF 文件数据,然后抽取出来当前需要哪一帧)。这个加载图片的过程是在异步线程进行的。
然后 FLAnimatedImage
会有一个内存区域专门放置这些渲染好的帧。 这时候,在主线程中的 ImageView
会根据当前需要,从这个内存区域中读取相应的帧。这是一个典型的 生产者-消费者
问题。
这样最大限度的保证主线程不去处理图片渲染的操作,并且我们刚才说的那个内存区域, 也是经过一系列的动态管理,以提升性能。 并且 FLAnimatedImage
的渲染线程,在数据没有准备好的时候,不会加锁等待,而是直接返回 nil。 这样也能避免一些实现中为了图片序列完全显示正确,而造成性能卡顿的问题。
这里给大家做了一个简要的介绍,关于 FLAnimatedImage
更详细的内容, 大家可以参考 Flipboard 的官方文档: http://engineering.flipboard.com/2014/05/animated-gif/
FLAnimatedImage
提供了一种更好的 GIF 图片渲染实践。 下次如果你的项目中需要使用 GIF 图片的时候,就可以考虑使用 FLAnimatedImage
来操作, 而不是用 UIWebView
费时费力的 hack 了。 大家如果有一些建议,或是更好的实践,也非常欢迎在留言中一起讨论。
如果你觉得这篇文章有帮助,还可以关注微信公众号 swift-cafe,会有更多我的原创内容分享给你~