Add completion handlers to all animate methods
This commit is contained in:
parent
7d627009f9
commit
0991ad36d8
|
@ -4,7 +4,6 @@
|
||||||
<adaptation id="fullscreen"/>
|
<adaptation id="fullscreen"/>
|
||||||
</device>
|
</device>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
@ -23,7 +22,7 @@
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Tap the image to pause/resume. Swipe to change GIF." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wsv-cU-WO5">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Tap the image to pause/resume. Swipe to change GIF." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wsv-cU-WO5">
|
||||||
<rect key="frame" x="95.5" y="124.5" width="185" height="29"/>
|
<rect key="frame" x="95" y="125" width="185" height="29"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="200" id="73c-sg-Egr"/>
|
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="200" id="73c-sg-Egr"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
@ -32,7 +31,7 @@
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<imageView clipsSubviews="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" placeholderIntrinsicWidth="600" placeholderIntrinsicHeight="300" translatesAutoresizingMaskIntoConstraints="NO" id="FSz-xF-Xds" customClass="GIFImageView" customModule="Gifu">
|
<imageView clipsSubviews="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" placeholderIntrinsicWidth="600" placeholderIntrinsicHeight="300" translatesAutoresizingMaskIntoConstraints="NO" id="FSz-xF-Xds" customClass="GIFImageView" customModule="Gifu">
|
||||||
<rect key="frame" x="0.0" y="203.5" width="375" height="300"/>
|
<rect key="frame" x="0.0" y="204" width="375" height="300"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" secondItem="FSz-xF-Xds" secondAttribute="height" multiplier="5:4" id="EOH-hn-KxM"/>
|
<constraint firstAttribute="width" secondItem="FSz-xF-Xds" secondAttribute="height" multiplier="5:4" id="EOH-hn-KxM"/>
|
||||||
|
@ -45,20 +44,30 @@
|
||||||
</connections>
|
</connections>
|
||||||
</imageView>
|
</imageView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Gifu" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c8Y-41-BaC">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Gifu" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c8Y-41-BaC">
|
||||||
<rect key="frame" x="170.5" y="100" width="34" height="20.5"/>
|
<rect key="frame" x="171" y="100" width="34" height="21"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||||
<color key="textColor" red="0.99144423007965088" green="0.56549066305160522" blue="0.033751130104064941" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.99144423007965088" green="0.56549066305160522" blue="0.033751130104064941" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XcY-7q-76n">
|
||||||
|
<rect key="frame" x="0.5" y="514" width="375" height="18"/>
|
||||||
|
<fontDescription key="fontDescription" type="italicSystem" pointSize="15"/>
|
||||||
|
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/>
|
<color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
<color key="tintColor" red="0.99144423007965088" green="0.56549066305160522" blue="0.033751130104064941" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="tintColor" red="0.99144423007965088" green="0.56549066305160522" blue="0.033751130104064941" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
<constraint firstItem="XcY-7q-76n" firstAttribute="width" secondItem="FSz-xF-Xds" secondAttribute="width" id="306-mf-Sm0"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="FSz-xF-Xds" secondAttribute="trailing" id="8kQ-x1-WJl"/>
|
<constraint firstAttribute="trailing" secondItem="FSz-xF-Xds" secondAttribute="trailing" id="8kQ-x1-WJl"/>
|
||||||
|
<constraint firstItem="XcY-7q-76n" firstAttribute="top" secondItem="FSz-xF-Xds" secondAttribute="bottom" constant="10" id="BH2-vh-hUc"/>
|
||||||
|
<constraint firstItem="XcY-7q-76n" firstAttribute="centerX" secondItem="FSz-xF-Xds" secondAttribute="centerX" id="FBH-PS-mfM"/>
|
||||||
<constraint firstItem="c8Y-41-BaC" firstAttribute="top" secondItem="jyV-Pf-zRb" secondAttribute="bottom" constant="80" id="JHy-q1-JuJ"/>
|
<constraint firstItem="c8Y-41-BaC" firstAttribute="top" secondItem="jyV-Pf-zRb" secondAttribute="bottom" constant="80" id="JHy-q1-JuJ"/>
|
||||||
<constraint firstAttribute="centerX" secondItem="c8Y-41-BaC" secondAttribute="centerX" id="Kc0-P5-KMZ"/>
|
<constraint firstAttribute="centerX" secondItem="c8Y-41-BaC" secondAttribute="centerX" id="Kc0-P5-KMZ"/>
|
||||||
<constraint firstItem="FSz-xF-Xds" firstAttribute="leading" secondItem="kh9-bI-dsS" secondAttribute="leading" id="O4L-QH-SvV"/>
|
<constraint firstItem="FSz-xF-Xds" firstAttribute="leading" secondItem="kh9-bI-dsS" secondAttribute="leading" id="O4L-QH-SvV"/>
|
||||||
<constraint firstItem="FSz-xF-Xds" firstAttribute="top" secondItem="wsv-cU-WO5" secondAttribute="bottom" constant="50" id="ODd-UW-Pca"/>
|
<constraint firstItem="FSz-xF-Xds" firstAttribute="top" secondItem="wsv-cU-WO5" secondAttribute="bottom" constant="50" id="ODd-UW-Pca"/>
|
||||||
|
<constraint firstItem="2fi-mo-0CV" firstAttribute="top" relation="greaterThanOrEqual" secondItem="XcY-7q-76n" secondAttribute="bottom" constant="12" id="VEE-1g-0W4"/>
|
||||||
<constraint firstItem="wsv-cU-WO5" firstAttribute="top" secondItem="c8Y-41-BaC" secondAttribute="bottom" constant="4" id="ZG4-fK-WvN"/>
|
<constraint firstItem="wsv-cU-WO5" firstAttribute="top" secondItem="c8Y-41-BaC" secondAttribute="bottom" constant="4" id="ZG4-fK-WvN"/>
|
||||||
<constraint firstAttribute="centerX" secondItem="FSz-xF-Xds" secondAttribute="centerX" id="oih-yH-vRh"/>
|
<constraint firstAttribute="centerX" secondItem="FSz-xF-Xds" secondAttribute="centerX" id="oih-yH-vRh"/>
|
||||||
<constraint firstAttribute="centerX" secondItem="wsv-cU-WO5" secondAttribute="centerX" id="yLb-zR-gfU"/>
|
<constraint firstAttribute="centerX" secondItem="wsv-cU-WO5" secondAttribute="centerX" id="yLb-zR-gfU"/>
|
||||||
|
@ -68,6 +77,7 @@
|
||||||
<nil key="simulatedTopBarMetrics"/>
|
<nil key="simulatedTopBarMetrics"/>
|
||||||
<nil key="simulatedBottomBarMetrics"/>
|
<nil key="simulatedBottomBarMetrics"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
<outlet property="imageDataLabel" destination="XcY-7q-76n" id="8b5-Hu-aDc"/>
|
||||||
<outlet property="imageView" destination="FSz-xF-Xds" id="gtV-MK-Fwd"/>
|
<outlet property="imageView" destination="FSz-xF-Xds" id="gtV-MK-Fwd"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
|
|
|
@ -3,19 +3,22 @@ import Gifu
|
||||||
|
|
||||||
class ViewController: UIViewController {
|
class ViewController: UIViewController {
|
||||||
@IBOutlet weak var imageView: GIFImageView!
|
@IBOutlet weak var imageView: GIFImageView!
|
||||||
|
@IBOutlet weak var imageDataLabel: UILabel!
|
||||||
@IBAction func unwindToRootViewController(segue: UIStoryboardSegue) { }
|
@IBAction func unwindToRootViewController(segue: UIStoryboardSegue) { }
|
||||||
|
|
||||||
var currentGIFName: String = "mugen" {
|
var currentGIFName: String = "mugen" {
|
||||||
didSet {
|
didSet {
|
||||||
imageView.animate(withGIFNamed: currentGIFName)
|
self.animate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func toggleAnimation(_ sender: AnyObject) {
|
@IBAction func toggleAnimation(_ sender: AnyObject) {
|
||||||
if imageView.isAnimatingGIF {
|
if imageView.isAnimatingGIF {
|
||||||
imageView.stopAnimatingGIF()
|
imageView.stopAnimatingGIF()
|
||||||
|
print(imageView.gifLoopDuration)
|
||||||
} else {
|
} else {
|
||||||
imageView.startAnimatingGIF()
|
imageView.startAnimatingGIF()
|
||||||
|
print(imageView.gifLoopDuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +36,14 @@ class ViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
imageView.animate(withGIFNamed: currentGIFName)
|
self.animate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func animate() {
|
||||||
|
imageView.animate(withGIFNamed: currentGIFName) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.imageDataLabel.text = self.currentGIFName.capitalized + " (\(self.imageView.frameCount) frames / \(String(format: "%.2f", self.imageView.gifLoopDuration))s)"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,12 +93,11 @@ public class Animator {
|
||||||
contentMode: contentMode,
|
contentMode: contentMode,
|
||||||
framePreloadCount: frameBufferCount,
|
framePreloadCount: frameBufferCount,
|
||||||
loopCount: loopCount)
|
loopCount: loopCount)
|
||||||
frameStore?.shouldResizeFrames = shouldResizeFrames
|
frameStore!.shouldResizeFrames = shouldResizeFrames
|
||||||
frameStore?.prepareFrames(completionHandler)
|
frameStore!.prepareFrames(completionHandler)
|
||||||
attachDisplayLink()
|
attachDisplayLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Add the display link to the main run loop.
|
/// Add the display link to the main run loop.
|
||||||
private func attachDisplayLink() {
|
private func attachDisplayLink() {
|
||||||
displayLink.add(to: .main, forMode: RunLoopMode.commonModes)
|
displayLink.add(to: .main, forMode: RunLoopMode.commonModes)
|
||||||
|
@ -128,11 +127,13 @@ public class Animator {
|
||||||
/// - parameter size: The target size of the individual frames.
|
/// - parameter size: The target size of the individual frames.
|
||||||
/// - parameter contentMode: The view content mode to use for the individual frames.
|
/// - parameter contentMode: The view content mode to use for the individual frames.
|
||||||
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
||||||
func animate(withGIFNamed imageName: String, size: CGSize, contentMode: UIViewContentMode, loopCount: Int = 0) {
|
/// - parameter completionHandler: Completion callback function
|
||||||
|
func animate(withGIFNamed imageName: String, size: CGSize, contentMode: UIViewContentMode, loopCount: Int = 0, completionHandler: (() -> Void)? = nil) {
|
||||||
prepareForAnimation(withGIFNamed: imageName,
|
prepareForAnimation(withGIFNamed: imageName,
|
||||||
size: size,
|
size: size,
|
||||||
contentMode: contentMode,
|
contentMode: contentMode,
|
||||||
loopCount: loopCount)
|
loopCount: loopCount,
|
||||||
|
completionHandler: completionHandler)
|
||||||
startAnimating()
|
startAnimating()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,11 +143,13 @@ public class Animator {
|
||||||
/// - parameter size: The target size of the individual frames.
|
/// - parameter size: The target size of the individual frames.
|
||||||
/// - parameter contentMode: The view content mode to use for the individual frames.
|
/// - parameter contentMode: The view content mode to use for the individual frames.
|
||||||
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
||||||
func animate(withGIFData imageData: Data, size: CGSize, contentMode: UIViewContentMode, loopCount: Int = 0) {
|
/// - parameter completionHandler: Completion callback function
|
||||||
|
func animate(withGIFData imageData: Data, size: CGSize, contentMode: UIViewContentMode, loopCount: Int = 0, completionHandler: (() -> Void)? = nil) {
|
||||||
prepareForAnimation(withGIFData: imageData,
|
prepareForAnimation(withGIFData: imageData,
|
||||||
size: size,
|
size: size,
|
||||||
contentMode: contentMode,
|
contentMode: contentMode,
|
||||||
loopCount: loopCount)
|
loopCount: loopCount,
|
||||||
|
completionHandler: completionHandler)
|
||||||
startAnimating()
|
startAnimating()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ class FrameStore {
|
||||||
animatedFrames.reserveCapacity(frameCount)
|
animatedFrames.reserveCapacity(frameCount)
|
||||||
preloadFrameQueue.async {
|
preloadFrameQueue.async {
|
||||||
self.setupAnimatedFrames()
|
self.setupAnimatedFrames()
|
||||||
if let handler = completionHandler { handler() }
|
completionHandler?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,29 +54,34 @@ extension GIFAnimatable {
|
||||||
///
|
///
|
||||||
/// - parameter imageName: The file name of the GIF in the main bundle.
|
/// - parameter imageName: The file name of the GIF in the main bundle.
|
||||||
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
||||||
public func animate(withGIFNamed imageName: String, loopCount: Int = 0) {
|
/// - parameter completionHandler: Completion callback function
|
||||||
|
public func animate(withGIFNamed imageName: String, loopCount: Int = 0, completionHandler: (() -> Void)? = nil) {
|
||||||
animator?.animate(withGIFNamed: imageName,
|
animator?.animate(withGIFNamed: imageName,
|
||||||
size: frame.size,
|
size: frame.size,
|
||||||
contentMode: contentMode,
|
contentMode: contentMode,
|
||||||
loopCount: loopCount)
|
loopCount: loopCount,
|
||||||
|
completionHandler: completionHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare for animation and start animating immediately.
|
/// Prepare for animation and start animating immediately.
|
||||||
///
|
///
|
||||||
/// - parameter imageData: GIF image data.
|
/// - parameter imageData: GIF image data.
|
||||||
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
||||||
public func animate(withGIFData imageData: Data, loopCount: Int = 0) {
|
/// - parameter completionHandler: Completion callback function
|
||||||
|
public func animate(withGIFData imageData: Data, loopCount: Int = 0, completionHandler: (() -> Void)? = nil) {
|
||||||
animator?.animate(withGIFData: imageData,
|
animator?.animate(withGIFData: imageData,
|
||||||
size: frame.size,
|
size: frame.size,
|
||||||
contentMode: contentMode,
|
contentMode: contentMode,
|
||||||
loopCount: loopCount)
|
loopCount: loopCount,
|
||||||
|
completionHandler: completionHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare for animation and start animating immediately.
|
/// Prepare for animation and start animating immediately.
|
||||||
///
|
///
|
||||||
/// - parameter imageURL: GIF image url.
|
/// - parameter imageURL: GIF image url.
|
||||||
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
/// - parameter loopCount: Desired number of loops, <= 0 for infinite loop.
|
||||||
public func animate(withGIFURL imageURL: URL, loopCount: Int = 0) {
|
/// - parameter completionHandler: Completion callback function
|
||||||
|
public func animate(withGIFURL imageURL: URL, loopCount: Int = 0, completionHandler: (() -> Void)? = nil) {
|
||||||
let session = URLSession.shared
|
let session = URLSession.shared
|
||||||
|
|
||||||
let task = session.dataTask(with: imageURL) { (data, response, error) in
|
let task = session.dataTask(with: imageURL) { (data, response, error) in
|
||||||
|
@ -85,7 +90,7 @@ extension GIFAnimatable {
|
||||||
print("Error downloading gif:", error.localizedDescription, "at url:", imageURL.absoluteString)
|
print("Error downloading gif:", error.localizedDescription, "at url:", imageURL.absoluteString)
|
||||||
case (let data?, _, _):
|
case (let data?, _, _):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.animate(withGIFData: data, loopCount: loopCount)
|
self.animate(withGIFData: data, loopCount: loopCount, completionHandler: completionHandler)
|
||||||
}
|
}
|
||||||
default: ()
|
default: ()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>135</string>
|
<string>136</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|
Loading…
Reference in New Issue