如何在Swift中加载GIF图像?


71

我有一个带有GIF横幅URL的字符串,需要将其放入应用程序中。

我的代码:

func showAdd(){
    Request.get("http://www.kyst.no/api/?apiMode=advertisement&lang=no", { (error: NSError?, data: NSData, text: NSString?) -> () in
        let jsonResult: Dictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as Dictionary<String, AnyObject>
        var banner : NSString = jsonResult["advertisement"]!["banner"] as NSString
        self.addViewImage.image = UIImage.animatedImageNamed(banner, duration: 1)
    })
}

但是什么也没发生。请帮忙。


animatedImageNamed()不按照您的想法去做。该方法是加载了一系列静态图像的快捷方式被命名为喜欢这样image0image 1image2等等,并将它们设置为animationImages阵列。它不会像GIF一样加载动画图像。这个问题以前曾被问过,并给出了一些答案:stackoverflow.com/questions/9744682/display-animated-gif-in-ios-鉴于它不是Swift,但将答案应用于Swift并不难。
Jasarien 2015年

如果您不想在上面链接的答案中使用开放源代码的ObjC代码,则基本要点是您需要解码gif文件以提取各个帧,然后将这些帧图像传递到图像视图的animationImages属性。
Jasarien 2015年

我也尝试过Expertland.net/question/a6bc48r3n7t5251n4v1p7l4n5u50jp6s9/… 但是我被卡住了:var testImage = UIImage.animatedImageWithAnimatedGIFData(NSData.dataWithContentsOfURL(url))'dataWithContentsOfURL'结构'DataOf'(')
Marius

您可以使用以下代码:github.com/kirualex/SwiftyGif
Sour LeangChhean

Answers:


134

加载GIF图像Swift:

##参考。

#1:从此链接复制swift文件 :

#2:使用名称加载GIF图像

    let jeremyGif = UIImage.gifImageWithName("funny")
    let imageView = UIImageView(image: jeremyGif)
    imageView.frame = CGRect(x: 20.0, y: 50.0, width: self.view.frame.size.width - 40, height: 150.0)
    view.addSubview(imageView)

#3:使用数据加载GIF图像

    let imageData = try? Data(contentsOf: Bundle.main.url(forResource: "play", withExtension: "gif")!)
    let advTimeGif = UIImage.gifImageWithData(imageData!)
    let imageView2 = UIImageView(image: advTimeGif)
    imageView2.frame = CGRect(x: 20.0, y: 220.0, width: 
    self.view.frame.size.width - 40, height: 150.0)
    view.addSubview(imageView2)

#4:使用URL加载GIF图像

    let gifURL : String = "http://www.gifbin.com/bin/4802swswsw04.gif"
    let imageURL = UIImage.gifImageWithURL(gifURL)
    let imageView3 = UIImageView(image: imageURL)
    imageView3.frame = CGRect(x: 20.0, y: 390.0, width: self.view.frame.size.width - 40, height: 150.0)
    view.addSubview(imageView3)

下载演示代码

输出:

iPhone 8 / iOS 11 / xCode 9

在此处输入图片说明


1
对于将来的用户,它将不适用于JPG或PNG。如果您正在加载URL列表,或者您不知道扩展名,则扩展名将失败。
A. Petrizza '18

15
这个lib使用了太多的内存,
morroko '18

2
successGIF.image = UIImage.gifImageWithName(“ translation-successful”)正在使用这样的名称,只是试图显示GIF。在这里我们只可以显示一次
Bhanuteja '18

8
@KiritModi这个图书馆使用了太多的内存,并且造成了很多内存泄漏
Samarth Kejriwal '18

1
如何调整动画速度?
法里斯·穆罕默德

20

本地gif的简单扩展。从gif获取所有图像,并将其添加到imageView animationImages。

extension UIImageView {
    static func fromGif(frame: CGRect, resourceName: String) -> UIImageView? {
        guard let path = Bundle.main.path(forResource: resourceName, ofType: "gif") else {
            print("Gif does not exist at that path")
            return nil
        }
        let url = URL(fileURLWithPath: path)
        guard let gifData = try? Data(contentsOf: url),
            let source =  CGImageSourceCreateWithData(gifData as CFData, nil) else { return nil }
        var images = [UIImage]()
        let imageCount = CGImageSourceGetCount(source)
        for i in 0 ..< imageCount {
            if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
                images.append(UIImage(cgImage: image))
            }
        }
        let gifImageView = UIImageView(frame: frame)
        gifImageView.animationImages = images
        return gifImageView
    }
}

使用方法:

 guard let confettiImageView = UIImageView.fromGif(frame: view.frame, resourceName: "confetti") else { return }
 view.addSubview(confettiImageView)
 confettiImageView.startAnimating()

使用UIImageView API进行重复和持续时间自定义。

confettiImageView.animationDuration = 3
confettiImageView.animationRepeatCount = 1

完成gif动画后,要释放内存。

confettiImageView.animationImages = nil

1
我使用这种方法在collectionView中加载了一些gif,而我的应用使用了超过2GB的内存。像这样使用gif似乎占用大量内存。
DidsData

1
原因CGImageSourceCreateWithData需要与CFRelease
愤怒的

@rage如何释放图像?当我尝试释放它时,xCode给我警告说CF对象是自动进行内存管理的。
摩卡(Mocha)

1
动画制作完成后,执行confettiImageView.animationImages = nil此操作将释放内存。
cbiggin

在高内存使用情况下,提取时缩小gif的每一帧可能会有所帮助,请尝试kCGImageSourceThumbnailMaxPixelSizeCGImageSourceCreateImageAtIndex()调用时指定选项,并键入通常等于UI组件的磅值乘以设备屏幕的比例因子的大小。
柯杨

14

首先安装一个吊舱:-

pod 'SwiftGifOrigin'

并导入您的班级

import SwiftGifOrigin

然后在viewDidiload方法中编写此代码

yourImageView.image = UIImage.gif(name: "imageName")

注意:-plz在gif文件名中不包括文件扩展名。例如:-

//Don't Do this
yourImageView.image = UIImage.gif(name: "imageName.gif")

参见源代码:https : //github.com/swiftgif/SwiftGif


6
对于该库的工作方式没有任何解释-如果该库突然开始出现故障,损坏或必须以其他方式删除它,应该如何继续显示GIF图像?请尝试解释库的功能。
royalmurder

错误:SwiftGif:此名为“ test”的图像不存在,我在资产中添加了test.gif,我可以看到该图像,但出现上述错误
karan

@karan,请使用:imageView.loadGif(asset: "test")
yoninja

我只使用了一个文件SwiftGifCommon / UIImage + Gif.swift和loadGif方法。无需安装完整的吊舱
Manish Nahar

由于该应用程序UI冻结了任何解决方案,因此在arkit场景中播放gif imageview时需要占用大量内存。
MIOSY

9
//
//  iOSDevCenters+GIF.swift
//  GIF-Swift
//
//  Created by iOSDevCenters on 11/12/15.
//  Copyright © 2016 iOSDevCenters. All rights reserved.
//
import UIKit
import ImageIO


extension UIImage {

public class func gifImageWithData(data: NSData) -> UIImage? {
    guard let source = CGImageSourceCreateWithData(data, nil) else {
        print("image doesn't exist")
        return nil
    }

    return UIImage.animatedImageWithSource(source: source)
}

public class func gifImageWithURL(gifUrl:String) -> UIImage? {
    guard let bundleURL = NSURL(string: gifUrl)
        else {
            print("image named \"\(gifUrl)\" doesn't exist")
            return nil
    }
    guard let imageData = NSData(contentsOf: bundleURL as URL) else {
        print("image named \"\(gifUrl)\" into NSData")
        return nil
    }

    return gifImageWithData(data: imageData)
}

public class func gifImageWithName(name: String) -> UIImage? {
    guard let bundleURL = Bundle.main
        .url(forResource: name, withExtension: "gif") else {
            print("SwiftGif: This image named \"\(name)\" does not exist")
            return nil
    }

    guard let imageData = NSData(contentsOf: bundleURL) else {
        print("SwiftGif: Cannot turn image named \"\(name)\" into NSData")
        return nil
    }

    return gifImageWithData(data: imageData)
}

class func delayForImageAtIndex(index: Int, source: CGImageSource!) -> Double {
    var delay = 0.1

    let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
    let gifProperties: CFDictionary = unsafeBitCast(CFDictionaryGetValue(cfProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque()), to: CFDictionary.self)

    var delayObject: AnyObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, Unmanaged.passUnretained(kCGImagePropertyGIFUnclampedDelayTime).toOpaque()), to: AnyObject.self)

    if delayObject.doubleValue == 0 {
        delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDelayTime).toOpaque()), to: AnyObject.self)
    }

    delay = delayObject as! Double

    if delay < 0.1 {
        delay = 0.1
    }

    return delay
}

class func gcdForPair(a: Int?, _ b: Int?) -> Int {
    var a = a
    var b = b
    if b == nil || a == nil {
        if b != nil {
            return b!
        } else if a != nil {
            return a!
        } else {
            return 0
        }
    }

    if a! < b! {
        let c = a!
        a = b!
        b = c
    }

    var rest: Int
    while true {
        rest = a! % b!

        if rest == 0 {
            return b!
        } else {
            a = b!
            b = rest
        }
    }
}

class func gcdForArray(array: Array<Int>) -> Int {
    if array.isEmpty {
        return 1
    }

    var gcd = array[0]

    for val in array {
        gcd = UIImage.gcdForPair(a: val, gcd)
    }

    return gcd
}

class func animatedImageWithSource(source: CGImageSource) -> UIImage? {
    let count = CGImageSourceGetCount(source)
    var images = [CGImage]()
    var delays = [Int]()

    for i in 0..<count {
        if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
            images.append(image)
        }

        let delaySeconds = UIImage.delayForImageAtIndex(index: Int(i), source: source)
        delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms
    }

    let duration: Int = {
        var sum = 0

        for val: Int in delays {
            sum += val
        }

        return sum
    }()

    let gcd = gcdForArray(array: delays)
    var frames = [UIImage]()

    var frame: UIImage
    var frameCount: Int
    for i in 0..<count {
        frame = UIImage(cgImage: images[Int(i)])
        frameCount = Int(delays[Int(i)] / gcd)

        for _ in 0..<frameCount {
            frames.append(frame)
        }
    }

    let animation = UIImage.animatedImage(with: frames, duration: Double(duration) / 1000.0)

    return animation
}
}

这是为Swift 3更新的文件


4
这个内存使用量异常高,只有一个较大的6mb gif,内存使用量已达到400MB。实际设备不是模拟器。虽然还没有尝试过许多其他的gif。
山姆兵

@SamBing我也遇到此代码的内存问题,您是否设法找到任何更新或其他替代方法?
Sujal

@Sujal我确实转到了一个名为Gifu的库,主要是因为它缓冲和处理内存的方式更有效。看一下它,因为我确实浏览了很多库,所以您可能只节省了一些时间。
山姆兵

1
@Sujal它支持从Data加载GIFS,因此您可以先获取Data。至于错误我真的不确定,因为我还没有遇到它。
山姆兵

1
@SamBing我确实尝试在单独的项目中使用Gifu,并使它正常工作。谢谢。我正在处理的项目使用的是“ SDWebImage”库,因此我更新了pod以获得gif支持,并显示了gif,内存消耗也很好。您也可以查看一下:)
Sujal,

3

您可以尝试这个新库。JellyGif尊重Gif帧的持续时间,同时具有很高的CPU和内存性能。它也与UITableViewCell和UICollectionViewCell一起很好地工作。要开始使用,您只需要

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))

有关更多信息,请查看其自述文件


3

如果有人告诉将gif放入任何文件夹而不是资产文件夹,那将是很好的


0

这对我有用

Podfile:

platform :ios, '9.0'
use_frameworks!

target '<Your Target Name>' do
pod 'SwiftGifOrigin', '~> 1.7.0'
end

用法:

// An animated UIImage
let jeremyGif = UIImage.gif(name: "jeremy")

// A UIImageView with async loading
let imageView = UIImageView()
imageView.loadGif(name: "jeremy")

// A UIImageView with async loading from asset catalog(from iOS9)
let imageView = UIImageView()
imageView.loadGif(asset: "jeremy")

有关更多信息,请单击以下链接:https : //github.com/swiftgif/SwiftGif


2
很多未解决的问题,最后一个代码大约在一年前提交的...这似乎是最新的:github.com/kaishin/Gifu
Starwave

1
已经有一个用户回答使用SwiftGiftOrigin
Mocha
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.