Improve configurability of the animator

This commit is contained in:
Reda Lemeden 2016-10-09 18:12:29 +02:00
parent 5b7de2ed2d
commit e029225c05
9 changed files with 250 additions and 23 deletions

View File

@ -8,7 +8,7 @@ public class Animator {
var shouldResizeFrames = false
/// Responsible for loading individual frames and resizing them if necessary.
var frameStore: FrameStore?
private var frameStore: FrameStore?
/// Tracks whether the display link is initialized.
private var displayLinkInitialized: Bool = false

View File

@ -76,7 +76,6 @@ extension GIFAnimatable {
animator?.prepareForAnimation(withGIFData: imageData, size: frame.size, contentMode: contentMode)
}
/// Stop animating and free up GIF data from memory.
public func prepareForReuse() {
animator?.prepareForReuse()
@ -92,6 +91,20 @@ extension GIFAnimatable {
animator?.stopAnimating()
}
/// Whether the frame images should be resized or not. The default is `false`, which means that the frame images retain their original size.
///
/// - parameter resize: Boolean value indicating whether individual frames should be resized.
public func setShouldResizeFrames(_ resize: Bool) {
animator?.shouldResizeFrames = resize
}
/// Sets the number of frames that should be buffered. Default is 50. A high number will result in more memory usage and less CPU load, and vice versa.
///
/// - parameter frames: The number of frames to buffer.
public func setFrameBufferCount(_ frames: Int) {
animator?.frameBufferCount = frames
}
/// Updates the image with a new frame if necessary.
public func updateImageIfNeeded() {
if var imageContainer = self as? ImageContainer {

View File

@ -19,7 +19,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>132</string>
<string>119</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>

View File

@ -595,6 +595,106 @@
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:FE4GifuPS_13GIFAnimatable21setShouldResizeFramesFSbT_"></a>
<a name="//apple_ref/swift/Method/setShouldResizeFrames(_:)" class="dashAnchor"></a>
<a class="token" href="#/s:FE4GifuPS_13GIFAnimatable21setShouldResizeFramesFSbT_">setShouldResizeFrames(_:)</a>
</code>
<span class="declaration-note">
Extension method
</span>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Whether the frame images should be resized or not. The default is <code>false</code>, which means that the frame images retain their original size.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">setShouldResizeFrames</span><span class="p">(</span><span class="n">_</span> <span class="nv">resize</span><span class="p">:</span> <span class="kt">Bool</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>resize</em>
</code>
</td>
<td>
<div>
<p>Boolean value indicating whether individual frames should be resized.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:FE4GifuPS_13GIFAnimatable19setFrameBufferCountFSiT_"></a>
<a name="//apple_ref/swift/Method/setFrameBufferCount(_:)" class="dashAnchor"></a>
<a class="token" href="#/s:FE4GifuPS_13GIFAnimatable19setFrameBufferCountFSiT_">setFrameBufferCount(_:)</a>
</code>
<span class="declaration-note">
Extension method
</span>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Sets the number of frames that should be buffered. Default is 50. A high number will result in more memory usage and less CPU load, and vice versa.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">setFrameBufferCount</span><span class="p">(</span><span class="n">_</span> <span class="nv">frames</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>frames</em>
</code>
</td>
<td>
<div>
<p>The number of frames to buffer.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>

View File

@ -595,6 +595,106 @@
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:FE4GifuPS_13GIFAnimatable21setShouldResizeFramesFSbT_"></a>
<a name="//apple_ref/swift/Method/setShouldResizeFrames(_:)" class="dashAnchor"></a>
<a class="token" href="#/s:FE4GifuPS_13GIFAnimatable21setShouldResizeFramesFSbT_">setShouldResizeFrames(_:)</a>
</code>
<span class="declaration-note">
Extension method
</span>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Whether the frame images should be resized or not. The default is <code>false</code>, which means that the frame images retain their original size.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">setShouldResizeFrames</span><span class="p">(</span><span class="n">_</span> <span class="nv">resize</span><span class="p">:</span> <span class="kt">Bool</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>resize</em>
</code>
</td>
<td>
<div>
<p>Boolean value indicating whether individual frames should be resized.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/s:FE4GifuPS_13GIFAnimatable19setFrameBufferCountFSiT_"></a>
<a name="//apple_ref/swift/Method/setFrameBufferCount(_:)" class="dashAnchor"></a>
<a class="token" href="#/s:FE4GifuPS_13GIFAnimatable19setFrameBufferCountFSiT_">setFrameBufferCount(_:)</a>
</code>
<span class="declaration-note">
Extension method
</span>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Sets the number of frames that should be buffered. Default is 50. A high number will result in more memory usage and less CPU load, and vice versa.</p>
</div>
<div class="declaration">
<h4>Declaration</h4>
<div class="language">
<p class="aside-title">Swift</p>
<pre class="highlight"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">setFrameBufferCount</span><span class="p">(</span><span class="n">_</span> <span class="nv">frames</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span></code></pre>
</div>
</div>
<div>
<h4>Parameters</h4>
<table class="graybox">
<tbody>
<tr>
<td>
<code>
<em>frames</em>
</code>
</td>
<td>
<div>
<p>The number of frames to buffer.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>

View File

@ -63,6 +63,8 @@
<p>Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It&rsquo;s also a <a href="https://goo.gl/maps/CCeAc">prefecture in Japan</a>).</p>
<p><strong>Swift 2.3</strong> support is on the <a href="https://github.com/kaishin/Gifu/tree/swift2.3">swift2.3</a> branch. <strong>This branch will not be getting any future updates</strong>.</p>
<p>⚠ What follows applies to the yet unreleased <code>2.0</code> on <code>master</code>.</p>
<a href='#install' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='install'>Install</h2>
<a href='#a-href-https-github-com-carthage-carthage-carthage-a' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h3 id='a-href-https-github-com-carthage-carthage-carthage-a'><a href="https://github.com/Carthage/Carthage">Carthage</a></h3>
@ -81,7 +83,7 @@ for up to date installation instructions.</li>
</ul>
<a href='#how-it-works' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='how-it-works'>How It Works</h2>
<p><code>Gifu</code> does not force you to use a specific subclass of <code>UIImageView</code>. The <code>Animator</code> class does the heavy-lifting, while the <code>GIFAnimatable</code> protocol exposes the functionality to the view classes that conform to it, using protocol extensions.</p>
<p><code>Gifu</code> does not force you to use the built-in <code>GIFImageView</code> subclass. The <code>Animator</code> does the heavy-lifting, while the <code>GIFAnimatable</code> protocol exposes the functionality to the view classes that conform to it, using protocol extensions.</p>
<p>The <code>Animator</code> has a <code>FrameStore</code> that only keeps a limited number of frames in-memory, effectively creating a buffer for the animation without consuming all the available memory. This approach makes loading large GIFs a lot more resource-friendly.</p>
@ -94,15 +96,12 @@ containing 10 frames, Gifu will load the current frame (red), buffer the next tw
<p>There are two options that should cover any situation:</p>
<ul>
<li>Use the built-in <code>GIFImageView</code> subclass.</li>
<li>Make any class conform to <code>GIFAnimatable</code>. Subclassing <code>UIImageView</code> is the easiest since you get most of the required properties for free.</li>
<li>Use the built-in <code>GIFImageView</code> subclass if you don&rsquo;t need to combine GIF support with another image library.</li>
<li>If you need more flexibility and composability, make your class conform to <code>GIFAnimatable</code>. In practice, any <code>UIView</code> subclass would do, since you get most of the required properties for free. For best results, make your <code>UIImageView</code> subclass conform to <code>GIFAnimatable</code> to get other niceties such as intrinsic content size.</li>
</ul>
<a href='#gifimageview' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h3 id='gifimageview'>GIFImageView</h3>
<p>A subclass of <code>UIImageView</code> that conforms to <code>GIFAnimatable</code>. You can use this class as-is or subclass it for further customization (not recommended).</p>
<a href='#gifanimatable' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h3 id='gifanimatable'>GIFAnimatable</h3>
<p>The bread and butter of Gifu. Through protocol extensions, <code>GIFAnimatable</code> exposes all the APIs of the library, and with very little boilerplate, any <code>UIImageView</code> subclass can conform to it.</p>
<p>The bread and butter of Gifu. Through protocol extensions, <code>GIFAnimatable</code> exposes all the APIs of the library, and with very little boilerplate, any class can conform to it.</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">MyImageView</span><span class="p">:</span> <span class="kt">UIImageView</span><span class="p">,</span> <span class="kt">GIFAnimatable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">animator</span><span class="p">:</span> <span class="kt">Animator</span><span class="p">?</span> <span class="o">=</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Animator</span><span class="p">(</span><span class="nv">withDelegate</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
@ -114,7 +113,7 @@ containing 10 frames, Gifu will load the current frame (red), buffer the next tw
<span class="p">}</span>
</code></pre>
<p>That&rsquo;s it. Now <code>MyImageView</code> is fully GIF-compatible, and any of these methods can be called on it:</p>
<p>That&rsquo;s it. Now <code>MyImageView</code> has access to all these methods and properties:</p>
<ul>
<li><code>prepareForAnimation(withGIFNamed:)</code> and <code>prepareForAnimation(withGIFData:)</code> to prepare the animator property for animation.</li>
@ -125,8 +124,16 @@ containing 10 frames, Gifu will load the current frame (red), buffer the next tw
<li><code>updateImageIfNeeded()</code> to update the image property if necessary.</li>
</ul>
<p>This approach is especially powerful when you want to combine the functionality of different image libraries.</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">MyImageView</span><span class="p">:</span> <span class="kt">OtherImageClass</span><span class="p">,</span> <span class="kt">GIFAnimatable</span> <span class="p">{}</span>
<p>Furthermore, you can make any class GIF-animatable, starting with <code>UIView</code> subclasses:</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">CustomAnimatedView</span><span class="p">:</span> <span class="kt">UIView</span><span class="p">,</span> <span class="kt">GIFAnimatable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">animator</span><span class="p">:</span> <span class="kt">Animator</span><span class="p">?</span> <span class="o">=</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Animator</span><span class="p">(</span><span class="nv">withDelegate</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
<span class="p">}()</span>
<span class="k">override</span> <span class="kd">public</span> <span class="kd">func</span> <span class="nf">display</span><span class="p">(</span><span class="n">_</span> <span class="nv">layer</span><span class="p">:</span> <span class="kt">CALayer</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">updateImageIfNeeded</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>Keep in mind that you need to have control over the class implementing <code>GIFAnimatable</code> since you cannot add the stored <code>Animator</code> property in an extension.</p>

Binary file not shown.

View File

@ -63,6 +63,8 @@
<p>Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It&rsquo;s also a <a href="https://goo.gl/maps/CCeAc">prefecture in Japan</a>).</p>
<p><strong>Swift 2.3</strong> support is on the <a href="https://github.com/kaishin/Gifu/tree/swift2.3">swift2.3</a> branch. <strong>This branch will not be getting any future updates</strong>.</p>
<p>⚠ What follows applies to the yet unreleased <code>2.0</code> on <code>master</code>.</p>
<a href='#install' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='install'>Install</h2>
<a href='#a-href-https-github-com-carthage-carthage-carthage-a' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h3 id='a-href-https-github-com-carthage-carthage-carthage-a'><a href="https://github.com/Carthage/Carthage">Carthage</a></h3>
@ -81,7 +83,7 @@ for up to date installation instructions.</li>
</ul>
<a href='#how-it-works' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='how-it-works'>How It Works</h2>
<p><code>Gifu</code> does not force you to use a specific subclass of <code>UIImageView</code>. The <code>Animator</code> class does the heavy-lifting, while the <code>GIFAnimatable</code> protocol exposes the functionality to the view classes that conform to it, using protocol extensions.</p>
<p><code>Gifu</code> does not force you to use the built-in <code>GIFImageView</code> subclass. The <code>Animator</code> does the heavy-lifting, while the <code>GIFAnimatable</code> protocol exposes the functionality to the view classes that conform to it, using protocol extensions.</p>
<p>The <code>Animator</code> has a <code>FrameStore</code> that only keeps a limited number of frames in-memory, effectively creating a buffer for the animation without consuming all the available memory. This approach makes loading large GIFs a lot more resource-friendly.</p>
@ -94,15 +96,12 @@ containing 10 frames, Gifu will load the current frame (red), buffer the next tw
<p>There are two options that should cover any situation:</p>
<ul>
<li>Use the built-in <code>GIFImageView</code> subclass.</li>
<li>Make any class conform to <code>GIFAnimatable</code>. Subclassing <code>UIImageView</code> is the easiest since you get most of the required properties for free.</li>
<li>Use the built-in <code>GIFImageView</code> subclass if you don&rsquo;t need to combine GIF support with another image library.</li>
<li>If you need more flexibility and composability, make your class conform to <code>GIFAnimatable</code>. In practice, any <code>UIView</code> subclass would do, since you get most of the required properties for free. For best results, make your <code>UIImageView</code> subclass conform to <code>GIFAnimatable</code> to get other niceties such as intrinsic content size.</li>
</ul>
<a href='#gifimageview' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h3 id='gifimageview'>GIFImageView</h3>
<p>A subclass of <code>UIImageView</code> that conforms to <code>GIFAnimatable</code>. You can use this class as-is or subclass it for further customization (not recommended).</p>
<a href='#gifanimatable' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h3 id='gifanimatable'>GIFAnimatable</h3>
<p>The bread and butter of Gifu. Through protocol extensions, <code>GIFAnimatable</code> exposes all the APIs of the library, and with very little boilerplate, any <code>UIImageView</code> subclass can conform to it.</p>
<p>The bread and butter of Gifu. Through protocol extensions, <code>GIFAnimatable</code> exposes all the APIs of the library, and with very little boilerplate, any class can conform to it.</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">MyImageView</span><span class="p">:</span> <span class="kt">UIImageView</span><span class="p">,</span> <span class="kt">GIFAnimatable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">animator</span><span class="p">:</span> <span class="kt">Animator</span><span class="p">?</span> <span class="o">=</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Animator</span><span class="p">(</span><span class="nv">withDelegate</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
@ -114,7 +113,7 @@ containing 10 frames, Gifu will load the current frame (red), buffer the next tw
<span class="p">}</span>
</code></pre>
<p>That&rsquo;s it. Now <code>MyImageView</code> is fully GIF-compatible, and any of these methods can be called on it:</p>
<p>That&rsquo;s it. Now <code>MyImageView</code> has access to all these methods and properties:</p>
<ul>
<li><code>prepareForAnimation(withGIFNamed:)</code> and <code>prepareForAnimation(withGIFData:)</code> to prepare the animator property for animation.</li>
@ -125,8 +124,16 @@ containing 10 frames, Gifu will load the current frame (red), buffer the next tw
<li><code>updateImageIfNeeded()</code> to update the image property if necessary.</li>
</ul>
<p>This approach is especially powerful when you want to combine the functionality of different image libraries.</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">MyImageView</span><span class="p">:</span> <span class="kt">OtherImageClass</span><span class="p">,</span> <span class="kt">GIFAnimatable</span> <span class="p">{}</span>
<p>Furthermore, you can make any class GIF-animatable, starting with <code>UIView</code> subclasses:</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">CustomAnimatedView</span><span class="p">:</span> <span class="kt">UIView</span><span class="p">,</span> <span class="kt">GIFAnimatable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">animator</span><span class="p">:</span> <span class="kt">Animator</span><span class="p">?</span> <span class="o">=</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Animator</span><span class="p">(</span><span class="nv">withDelegate</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
<span class="p">}()</span>
<span class="k">override</span> <span class="kd">public</span> <span class="kd">func</span> <span class="nf">display</span><span class="p">(</span><span class="n">_</span> <span class="nv">layer</span><span class="p">:</span> <span class="kt">CALayer</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">updateImageIfNeeded</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>Keep in mind that you need to have control over the class implementing <code>GIFAnimatable</code> since you cannot add the stored <code>Animator</code> property in an extension.</p>