Wie lade ich ein GIF-Bild in Swift?

71

Ich habe einen String mit einer URL des GIF-Banners, den ich in die App einfügen muss.

Mein Code:

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

Aber nichts passiert. Bitte helfen Sie.

Marius
quelle
animatedImageNamed()tut nicht das, was du denkst. Dieses Verfahren ist eine Abkürzung für eine Reihe von statischen Bildern , die wie das Laden so benannt sind image0, image 1, image2und so weiter und setzt sie als animationImagesArray. Es wird kein animiertes Bild wie ein GIF geladen. Diese Frage wurde bereits gestellt und hat einige Antworten: stackoverflow.com/questions/9744682/display-animated-gif-in-ios - vorausgesetzt , es ist nicht Swift, aber es sollte nicht schwierig sein, die Antworten auf Swift anzuwenden.
Jasarien
Wenn Sie den Open-Source-ObjC-Code in der oben verlinkten Antwort nicht verwenden möchten, müssen Sie die GIF-Datei dekodieren, um die einzelnen Frames zu extrahieren, und diese Frame-Bilder dann an die animationImagesEigenschaft der Bildansicht übergeben .
Jasarien
Ich habe auch versucht , expertland.net/question/a6bc48r3n7t5251n4v1p7l4n5u50jp6s9/... Aber ich stecken bleiben auf: var = Testbilder UIImage.animatedImageWithAnimatedGIFData (NSData.dataWithContentsOfURL (url)) 'dataWithContentsOfURL' ist nicht verfügbar: Verwendung Objektbau 'NSData (contentsOfURL :)'
Marius
Sie können dieses verwenden: github.com/kirualex/SwiftyGif
Sour LeangChhean
Bitte beziehen Sie sich auf diese stackoverflow.com/a/50517364/3827479
Sukwon

Antworten:

134

GIF-Bild laden Swift:

## Referenz.

# 1: Kopieren Sie die schnelle Datei von diesem Link :

# 2: Laden Sie das GIF-Bild mit dem Namen

    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-Bild mit Daten laden

    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: GIF-Bild über URL laden

    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)

Laden Sie den Demo-Code herunter

AUSGABE :

iPhone 8 / iOS 11 / xCode 9

Geben Sie hier die Bildbeschreibung ein

Kirit Modi
quelle
1
Für zukünftige Benutzer funktioniert dies nicht mit JPG oder PNG. Wenn Sie eine Liste von URLs laden oder die Erweiterung nicht kennen, schlägt dies fehl.
A. Petrizza
15
Diese
Bibliothek verbraucht
2
successGIF.image = UIImage.gifImageWithName ("Übersetzung erfolgreich") verwendet so, nur mit Name versuche ich, GIF anzuzeigen. Hier, wie können wir nur einmal zeigen
Bhanuteja
8
@ KiritModi diese Bibliothek verwendet zu viel Speicher und gibt viele Speicherlecks
Samarth Kejriwal
1
Wie stelle ich die Animationsgeschwindigkeit ein?
Faris Muhammed
20

Einfache Erweiterung für lokale Gifs. Ruft alle Bilder aus dem GIF ab und fügt sie den imageView animationImages hinzu.

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

Benutzen:

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

Wiederholungs- und Daueranpassungen mithilfe von UIImageView-APIs.

confettiImageView.animationDuration = 3
confettiImageView.animationRepeatCount = 1

Wenn Sie mit dem Animieren des GIF fertig sind und den Speicher freigeben möchten.

confettiImageView.animationImages = nil
Mokka
quelle
1
Ich habe diesen Ansatz verwendet, um ein paar Gifs in eine collectionView zu laden, und meine App verwendete über 2 GB Speicher. Die Verwendung solcher Gifs scheint extrem speicherintensiv zu sein.
DoesData
1
Ursache CGImageSourceCreateWithData muss mit einem ausgeglichen werdenCFRelease
ragt
@rage Wie veröffentliche ich das Bild? Wenn ich versuche, es freizugeben, gibt xCode eine Warnung aus, dass CF-Objekte automatisch speicherverwaltet werden.
Mokka
1
Wenn Sie mit Ihrer Animation fertig sind, confettiImageView.animationImages = nilwird der Speicher freigegeben.
cbiggin
Das Verkleinern jedes GIF-Frames während des Extrahierens kann bei hoher Speichernutzung hilfreich sein. Versuchen Sie, die Option mit dem kCGImageSourceThumbnailMaxPixelSizeSchlüssel beim CGImageSourceCreateImageAtIndex()Aufruf anzugeben. Wählen Sie normalerweise eine Größe, die der Punktgröße der UI-Komponente multipliziert mit dem Skalierungsfaktor des Gerätebildschirms entspricht.
Ke Yang
14

Installieren Sie zuerst einen Pod: -

pod 'SwiftGifOrigin'

und in Ihre Klasse importieren

import SwiftGifOrigin

Schreiben Sie dann diesen Code in die viewDidiload-Methode

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

Hinweis: - Bitte fügen Sie die Dateierweiterung nicht in den GIF-Dateinamen ein. Ex:-

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

Siehe Quelle: https://github.com/swiftgif/SwiftGif

Sagar Sangani
quelle
6
Es gibt keine Erklärung dafür, wie diese Bibliothek funktioniert - wie soll jemand weiterhin ein GIF-Bild anzeigen, wenn diese Bibliothek plötzlich ausfällt oder beschädigt wird oder wenn er es anderweitig entfernen muss? Bitte versuchen Sie zu erklären, was die Bibliothek tut.
Royalmurder
funktioniert nicht für mich Fehler: SwiftGif: Dieses Bild mit dem Namen "test" existiert nicht. Ich habe test.gif in Assets hinzugefügt. Ich kann das Bild sehen, aber ich erhalte den obigen Fehler
Karan
@ Karan, verwenden Sie diese:imageView.loadGif(asset: "test")
Yoninja
Ich habe nur eine Datei SwiftGifCommon / UIImage + Gif.swift und loadGif verwendet. Keine Notwendigkeit, kompletten Pod zu installieren
Manish Nahar
Es braucht viel Speicher, wenn ich GIF-Bildansicht in einer Arkit-Szene spiele, weil diese App-Benutzeroberfläche eine Lösung eingefroren hat?
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
}
}

Hier ist die Datei für Swift 3 aktualisiert

Zach Doster
quelle
4
Die Speichernutzung in diesem Fall ist ungewöhnlich hoch. Mit einer einzigen größeren Speicherkapazität von 6 MB wird die Speichernutzung auf 400 MB erhöht. Tatsächliches Gerät kein Simulator. Ich habe noch nicht viele andere Gifs ausprobiert.
Sam Bing
@SamBing Ich bin auch mit dem Speicherproblem mit diesem Code konfrontiert. Haben Sie es geschafft, ein Update oder andere Alternativen dazu zu finden?
Sujal
@Sujal Ich habe mich an eine Bibliothek namens Gifu gewandt, hauptsächlich weil die Art und Weise, wie sie Speicher puffert und handhabt, viel effizienter ist. Schauen Sie es sich an, da ich viele Bibliotheken durchgesehen habe, können Sie einfach etwas Zeit sparen.
Sam Bing
1
@Sujal unterstützt das Laden von GIFS aus Daten, sodass Sie die Daten zuerst abrufen können. Was den Fehler betrifft, bin ich mir wirklich nicht sicher, da ich ihn nicht gefunden habe.
Sam Bing
1
@ SamBing Ich habe versucht, Gifu in einem separaten Projekt zu verwenden und es zum Laufen gebracht. Vielen Dank. Das Projekt, an dem ich arbeite, verwendet die Bibliothek 'SDWebImage', daher habe ich den Pod für die GIF-Unterstützung aktualisiert und die GIFs angezeigt. Der Speicherverbrauch ist ebenfalls in Ordnung. Sie können auch einen Blick darauf werfen :)
Sujal
3

Sie können diese neue Bibliothek ausprobieren . JellyGif respektiert die Gif-Frame-Dauer und bietet gleichzeitig eine hohe CPU- und Speicherleistung. Es funktioniert auch hervorragend mit UITableViewCell & UICollectionViewCell. Um loszulegen, müssen Sie nur

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

Weitere Informationen finden Sie in der README-Datei

Linh Ta
quelle
3

Es wäre großartig, wenn jemand sagen würde, er solle gif in einen beliebigen Ordner anstatt in einen Assets-Ordner legen

Smoothumut
quelle
0

Das funktioniert bei mir

Podfile:

platform :ios, '9.0'
use_frameworks!

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

Verwendung:

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

Weitere Informationen finden Sie unter folgendem Link: https://github.com/swiftgif/SwiftGif

Arjun
quelle
2
Viele offene Probleme, letzter Code wurde vor ungefähr einem Jahr festgeschrieben ... Dies scheint aktueller zu sein: github.com/kaishin/Gifu
Starwave
1
Es gibt bereits einen Benutzer, der mit SwiftGiftOrigin geantwortet hat
Mocha