• Stars
    star
    3,084
  • Rank 14,587 (Top 0.3 %)
  • Language
    Swift
  • License
    Other
  • Created about 10 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

High-performance animated GIF support for iOS in Swift

Logo

Test GitHub release Carthage compatible Swift 5.0 platforms

Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It's also a prefecture in Japan).

Install

Swift Package Manager

Add the following to your Package.swift file:

let package = Package(
    dependencies: [
    .package(url: "https://github.com/kaishin/Gifu.git", from: "3.2.2")
    ],
)

Carthage

  • Add the following to your Cartfile: github "kaishin/Gifu"
  • Then run carthage update
  • Follow the current instructions in Carthage's README for up to date installation instructions.

CocoaPods

  • Add the following to your Podfile: pod 'Gifu'
  • You will also need to make sure you're opting into using frameworks: use_frameworks!
  • Then run pod install with CocoaPods 0.36 or newer.

How It Works

Gifu does not require using the built-in GIFImageView subclass. The Animator class does the heavy-lifting, while the GIFAnimatable protocol exposes the functionality to the view classes that conform to it, using protocol extensions.

The Animator has a FrameStore 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.

The figure below summarizes how this works in practice. Given an image containing 10 frames, Gifu will load the current frame (red), buffer the next two frames in this example (orange), and empty up all the other frames to free up memory (gray):

Usage

There are two options that should cover any situation:

  • Use the built-in GIFImageView subclass if you don't need to combine GIF support with another image library.
  • If you need more flexibility and composability, make your class conform to GIFAnimatable. In practice, any UIView subclass would do, since you get most of the required properties for free. For best results, make your UIImageView subclass conform to GIFAnimatable to get access to other features such as intrinsic content size.

GIFAnimatable

The bread and butter of Gifu. Through protocol extensions, GIFAnimatable exposes all the APIs of the library, and with very little boilerplate, any class can conform to it.

class MyImageView: UIImageView, GIFAnimatable {
  public lazy var animator: Animator? = {
    return Animator(withDelegate: self)
  }()

  override public func display(_ layer: CALayer) {
    updateImageIfNeeded()
  }
}

That's it. Now MyImageView has access to all these methods and properties:

  • prepareForAnimation(withGIFNamed:) and prepareForAnimation(withGIFData:) to prepare the animator property for animation.
  • startAnimatingGIF() and stopAnimatingGIF() to control the animation.
  • animate(withGIFNamed:) and animate(withGIFData:) to prepare for animation and start animating immediately.
  • frameCount, isAnimatingGIF, and activeFrame to inspect the GIF view.
  • prepareForReuse() to free up resources.
  • updateImageIfNeeded() to update the image property if necessary.

Furthermore, you can make any class GIF-animatable, starting with UIView subclasses:

class CustomAnimatedView: UIView, GIFAnimatable {
  public lazy var animator: Animator? = {
    return Animator(withDelegate: self)
  }()

  override public func display(_ layer: CALayer) {
    updateImageIfNeeded()
  }
}

You can also make UIKit classes conform using associated objects may you wish:

import UIKit
import Gifu

extension UIImageView: GIFAnimatable {
  private struct AssociatedKeys {
    static var AnimatorKey = "gifu.animator.key"
  }

  override open func display(_ layer: CALayer) {
    updateImageIfNeeded()
  }

  public var animator: Animator? {
    get {
      guard let animator = objc_getAssociatedObject(self, &AssociatedKeys.AnimatorKey) as? Animator else {
        let animator = Animator(withDelegate: self)
        self.animator = animator
        return animator
      }

      return animator
    }

    set {
      objc_setAssociatedObject(self, &AssociatedKeys.AnimatorKey, newValue as Animator?, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
  }
}

Examples

The simplest way to get started is initializing a GIFAnimatable class in code or in a storyboard, then calling animate(:) on it.

let imageView = GIFImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
imageView.animate(withGIFNamed: "mugen") {
  print("It's animating!")
}

You can also prepare for the animation when the view loads and only start animating after a user interaction.

// In your view controller..

override func viewDidLoad() {
  super.viewDidLoad()
  imageView.prepareForAnimation(withGIFNamed: "mugen") {
    print("Ready to animate!")
  }
}

@IBAction func toggleAnimation(_ sender: AnyObject) {
  if imageView.isAnimatingGIF {
    imageView.stopAnimatingGIF()
  } else {
    imageView.startAnimatingGIF()
  }
}

If you are using a GIFAnimatable class in a table or collection view, you can call the prepareForReuse() method in your cell subclass:

override func prepareForReuse() {
  super.prepareForReuse()
  imageView.prepareForReuse()
}

Demo App

Clone or download the repository and open Demo/Demo.xcworkspace to check out the demo app.

Documentation

See the full API documentation.

Compatibility

  • iOS 9.0+
  • Swift 4.0
  • Xcode 9.0

License

See LICENSE.

More Repositories

1

ImageScout

A Swift implementation of fastimage. Supports PNG, GIF, and JPEG.
Swift
975
star
2

markoff

A lightweight Markdown (CommonMark) previewer for macOS.
Swift
797
star
3

Verbena

Get UIImage/NSImage instances from Quartz drawing code or UIView/NSView
Swift
97
star
4

custom-UIButton

Different methods to customize a UIButton
Objective-C
92
star
5

Nope

Blazing fast content blocking for Safari 9+.
JavaScript
60
star
6

syndicate

Safari extension that brings the RSS button back to the toolbar.
HTML
42
star
7

MacIconPreviewer

Figure out which icons are used in which context in OS X
Swift
34
star
8

Setup

Setup for new Macs.
JavaScript
23
star
9

Kroma

A collection of color helpers for SwiftUI.
Swift
17
star
10

Thyme

A functional, descriptive, and more modern CoreGraphics wrapper for iOS/OS X.
Swift
16
star
11

swiftbits

Swift snippets, tips, resources, and links.
CSS
12
star
12

github-notifications-bitbar

A bitbar plugin to show GitHub notifications directly in the macOS menu bar.
Swift
10
star
13

redalemeden.com

Source of redalemeden.com
JavaScript
10
star
14

water.scss

A highly experimental Sass micro library
CSS
9
star
15

dotfiles

These are my dotfiles.
Vim Script
6
star
16

retina-examples

Live examples of different client-side techniques to serve retina-ready images on the web.
JavaScript
5
star
17

swiftui.directory

The source of SwiftUI Directory
JavaScript
5
star
18

generator-moule

/mul/ A static site Yeoman mold using Gulp & Jekyll
JavaScript
5
star
19

pip-my-safari

Alfred workflow to enable PiP mode for videos in Safari.
5
star
20

jekyll-theme-appcast

A Jekyll theme to generate macOS appcast feeds and changelog pages.
HTML
3
star
21

svelte-starter

A static site starter with Svelte and SvelteKit
JavaScript
3
star
22

RESTClient

An async/await based REST API client using function composition
Swift
3
star
23

Presentations

Slides of my previous talks.
Swift
3
star
24

Glyfons

Open-source glyph icon set/kit.
JavaScript
2
star
25

unredacted

Blog about technology and design.
HTML
1
star
26

json-feed-jekyll

A spec-compliant https://jsonfeed.org template for your Jekyll-generated blog.
1
star