Lightweight, performant, and memory efficient Gif framework
#source 'https://cocoapods.org/pods/JellyGif'
use_frameworks!
pod 'JellyGif'
The easiest way to get started is using JellyGifImageView
and calling startGif(with:)
import JellyGif
let imageView = JellyGifImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
//Animates Gif from the main bundle
imageView.startGif(with: .name("Gif name"))
//Animates Gif with a local path
let url = URL(string: "Gif path")!
imageView.startGif(with: .localPath(url))
//Animates Gif with data
imageView.startGif(with: .data(Data))
To fully utilize full power of JellyGif, use JellyGifAnimator
and conform to its JellyGifAnimatorDelegate
import JellyGif
let imageView = UIImageView(CGRect(x: 0, y: 0, width: 100, height: 100))
let animator = JellyGifAnimator(imageInfo: .name("Gif name"), pixelSize: .custom(350), animationQuality: .best)
animator.delegate = self
//JellyGifAnimatorDelegate
func gifAnimatorIsReady(_ sender: JellyGifAnimator) {
sender.startAnimation()
}
func imageViewForAnimator(_ sender: JellyGifAnimator) -> UIImageView? {
return imageView
}
func gifAnimatorDidChangeImage(_ image: UIImage, sender: JellyGifAnimator) {
//Use this method if you want to manually update Gif frame instead of using an UIImageView
}
JellyGifAnimator
let you control every aspect of a Gif including its maximum output size - pixelSize
and its frames per second - animationQuality
. The closer the pixelSize
property is to the actual size of the image holder the smaller the memory footprint and the better the CPU performance.
To use JellyGifAnimator
with an UICollectionView
or an UITableView
, create a dictionary of JellyGifAnimator
inside the owner of the UICollectionView
or UITableView
and conform to JellyGifAnimatorDelegate
import JellyGif
class ViewController: UIViewController {
var gifNames: [String] = []
var animators: [IndexPath: JellyGifAnimator] = [:]
//Your code
//...
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
//Your Code
//...
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//dequeue cell
//...
let gifName = gifNames[indexPath.item]
if animators[indexPath] == nil {
let animator = JellyGifAnimator(imageInfo: .name(gifName), pixelSize: .custom(350), animationQuality: .best)
animators[indexPath] = animator
}
//If the Gif is not ready, show a placeholder image - which is the first frame of the Gif instead
if animators[indexPath]?.isReady != true {
cell.imageView.image = animators[indexPath]?.placeholder
}
animators[indexPath]?.delegate = self
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if animators[indexPath]?.isReady == true {
animators[indexPath]?.startAnimation()
} else {
animators[indexPath]?.prepareAnimation()
}
}
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
//Pause animation and the preparation process if the cell is not visible
animators[indexPath]?.pauseAnimation()
animators[indexPath]?.stopPreparingAnimation()
}
}
extension ViewController: JellyGifAnimatorDelegate {
func gifAnimatorIsReady(_ sender: JellyGifAnimator) {
sender.startAnimation()
}
func imageViewForAnimator(_ sender: JellyGifAnimator) -> UIImageView? {
for indexPath in collectionView.indexPathsForVisibleItems {
if animators[indexPath] === sender {
return (collectionView.cellForItem(at: indexPath) as? YourCustomCell)?.imageView
}
}
return nil
}
}
CPU Usage | Memory Usage | |
---|---|---|
SwiftyGif | 2% | 44.6Mb |
Gifu | 2% | 46.3Mb |
JellyGif | 1% | 46.3Mb |
JellyGif (optimized mode on) | 1% | 30.3Mb |
CPU Usage | Memory Usage | |
---|---|---|
SwiftyGif | 34% | 31.7Mb |
Gifu | 6% | 200Mb |
JellyGif | 6% | 200Mb |
JellyGif (optimized mode on) | 5% | 39.1Mb |
Measured on an iPhone Xs Max, iOS 13.3.1 and Xcode 11.3.1