FLAnimatedImage - GIF 图片最佳实践
LoreneMJT
8年前
<p>GIF 图片在 Web 时代是一种广泛使用的图片格式。 但在 iOS 中,原生库直到现在也没有提供对 GIF 比较完善的支持。 FLAnimatedImage 这个库正式专门为 iOS App 中显示 GIF 图片而来的。</p> <h2>FLAnimatedImage 简介</h2> <p>FLAnimatedImage 是 Flipboard 团队开发的在它们 App 中渲染 GIF 图片使用的库。 后来 Flipboard 将 FLAnimatedImage 开源出来供大家使用。 所以你不用担心它在实践中会不会出现问题, 毕竟已经在 Flipboard 这种 App 上面经过充分的实践验证了。</p> <p>因为 Flipboard App 中很多频道会展示大量的 GIF 图片,而 iOS 原生的系统库中并没有提供对 GIF 很好的支持,所以 FLAnimatedImage 就应运而生了。</p> <h2>基本思路</h2> <p>大家如果在 iOS 中处理过 GIF 图片, 如果通过原生系统提供的能力, 可能只有两种方式。 并且这两种方式都不是专门针对于 GIF 的解决方案,更像是一种 hack。</p> <p>第一种方式, UIImage 虽然提供了一种创建连续切换的动画图片的能力, 但这个能力更像是为了那些简单动画而服务的。 比如加载数据时候显示的 loading 图片。 如果将 GIF 图片通过这种能力来显示,会带来诸多问题。</p> <p>第二种方式,可能是大家用的最多的了。 就是创建一个 UIWebView 然后在这里面把 GIF 显示出来。 但从原理上来想, UIWebView 并不是为了显示 GIF 图片而生的。 其实也算不上最佳实践。</p> <p>但 iOS 原生系统库目前只提供了这几个能力, 用这些 hack 方式也是无奈之举。</p> <h2>使用 FLAnimatedImage</h2> <p>给大家介绍了基本的问题背景, 咱们就来看看 FLAnimatedImage 是如何解决这个问题的吧。 我们可以通过Carthage 将 FLAnimatedImage 集成进来, 创建这样一个 Cartfile :</p> <pre> <code class="language-objectivec">github "Flipboard/FLAnimatedImage" </code></pre> <p>然后执行:</p> <pre> <code class="language-objectivec">carthage update </code></pre> <p>就可以将 FLAnimatedImage 拉取下来。</p> <p>如果你使用的 Swift 可以在 Bridgeing Header 中引入 FLAnimatedImage :</p> <pre> <code class="language-objectivec">#import <FLAnimatedImage/FLAnimatedImage.h> </code></pre> <p>随后在需要的地方这样调用 FLAnimatedImage 就可以了:</p> <pre> <code class="language-objectivec">//创建 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() } </code></pre> <p>这里给大家简单讲解一下, 首先我们初始化一个 FLAnimatedImageView 实例。 然后 URLSession 读取图片数据, 得到图片的数据 data 后, 用这个数据初始化 FLAnimatedImage 实例, 最后将它设置给 animatedImage 属性。 这样就完成了, 其余的 GIF 渲染工作都由 FLAnimatedImage 来处理。</p> <p>上面的代码应该比较简明易懂,如果有疑问可以在留言中提出~</p> <h2>GIF 渲染原理</h2> <p>为什么说 FLAnimatedImage 相对于 iOS 原生的几种 hack 方式更趋近于最佳实践呢? 咱们简单聊聊 FLAnimatedImage 渲染 GIF 图片的原理。 FLAnimatedImage 会有两个线程同时在运转。 其中一个线程负责渲染 GIF 的每一帧的图片内容(所谓的渲染,大体上就是加载 GIF 文件数据,然后抽取出来当前需要哪一帧)。这个加载图片的过程是在异步线程进行的。</p> <p>然后 FLAnimatedImage 会有一个内存区域专门放置这些渲染好的帧。 这时候,在主线程中的 ImageView 会根据当前需要,从这个内存区域中读取相应的帧。这是一个典型的 <strong>生产者-消费者</strong> 问题。</p> <p>这样最大限度的保证主线程不去处理图片渲染的操作,并且我们刚才说的那个内存区域, 也是经过一系列的动态管理,以提升性能。 并且 FLAnimatedImage 的渲染线程,在数据没有准备好的时候,不会加锁等待,而是直接返回 nil。 这样也能避免一些实现中为了图片序列完全显示正确,而造成性能卡顿的问题。</p> <h2>结语</h2> <p>FLAnimatedImage 提供了一种更好的 GIF 图片渲染实践。 下次如果你的项目中需要使用 GIF 图片的时候,就可以考虑使用 FLAnimatedImage 来操作, 而不是用 UIWebView 费时费力的 hack 了。 大家如果有一些建议,或是更好的实践,也非常欢迎在留言中一起讨论。</p> <p> </p> <p>来自:http://www.swiftcafe.io/2016/12/08/fl-image/</p> <p> </p>