在iPhone的UIImageView中添加动态GIF图像

82

我需要从 URL 中加载一个动态的 Gif 图片并且显示在 UIImageview 上。

当我使用正常的代码时,这张图片没有加载出来。

是否有其他方法可以加载动态的 Gif 图片呢?


我需要从以下URL中加载图像到UIImageview中... http://feedads.g.doubleclick.net/~at/K_fHnmr7a7T0pru2TjQC29TsPYY/1/di - Velmurugan
请点击以下链接查看有关Swift的内容: https://dev59.com/z14c5IYBdhLWcg3wc5_r - Mr.Javed Multani
14个回答

141
UIImageView* animatedImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
animatedImageView.animationImages = [NSArray arrayWithObjects:    
                               [UIImage imageNamed:@"image1.gif"],
                               [UIImage imageNamed:@"image2.gif"],
                               [UIImage imageNamed:@"image3.gif"],
                               [UIImage imageNamed:@"image4.gif"], nil];
animatedImageView.animationDuration = 1.0f;
animatedImageView.animationRepeatCount = 0;
[animatedImageView startAnimating];
[self.view addSubview: animatedImageView];

您可以加载多个gif图像。

您可以使用以下ImageMagick命令来拆分gif:

convert +adjoin loading.gif out%d.gif

1
我需要从以下URL中加载图像到UIImageview中... http://feedads.g.doubleclick.net/~at/K_fHnmr7a7T0pru2TjQC29TsPYY/1/di - Velmurugan
NSData *mydata = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:myurl]]; UIImage *myimage = [[UIImage alloc] initWithData:imageData]; 使用此代码从 URL 读取数据,然后将该对象添加到数组中。 - Ishu
9
iPhone OS无法正确地显示动态GIF图像,UIImage对象不能用于此目的。即使支持GIF图像,任何动画都将被丢弃,只会显示第一帧。 因此,如果您需要在iPhone应用程序中显示动态GIF,则需要编写代码。请参考这里:http://www.pliep.nl/blog/2009/04/iphone_developer_decoding_an_animated_gif_image_in_objc - fyasar
11
请使用 Web View 而不是 Image View。 - Shreesh Garg
2
https://github.com/mayoff/uiimage-from-animated-gif 只需使用此类别,因为它会自动执行答案中描述的所有操作。 - Michael

52

这已经找到了一个被接受的答案,但我最近发现了UIImage+animatedGIF UIImage扩展。它提供了以下类别:

+[UIImage animatedImageWithAnimatedGIFURL:(NSURL *)url]

让您可以轻松地:

#import "UIImage+animatedGIF.h"
UIImage* mygif = [UIImage animatedImageWithAnimatedGIFURL:[NSURL URLWithString:@"http://en.wikipedia.org/wiki/File:Rotating_earth_(large).gif"]];

神奇般的工作。


1
有没有办法直接在项目中使用文件,而不是从URL加载gif? - juliensaad
2
UIImage+animatedGIF...是我见过的最好的类别之一...感谢@robmayoff - whyoz

23

以下是使用 Gif 图像的最佳解决方案。 在您的项目中从 Github 添加 SDWebImage。

#import "UIImage+GIF.h"

_imageViewAnimatedGif.image= [UIImage sd_animatedGIFNamed:@"thumbnail"];

这正是我一直在寻找的。谢谢你!如果我可以补充一点:UIImageView没有被合成,但应该在Storyboard中创建并链接到它的IBOutlet :) - Lucia Belardinelli

14

如果您不想使用第三方库,

extension UIImageView {
    func setGIFImage(name: String, repeatCount: Int = 0 ) {
        DispatchQueue.global().async {
            if let gif = UIImage.makeGIFFromCollection(name: name, repeatCount: repeatCount) {
                DispatchQueue.main.async {
                    self.setImage(withGIF: gif)
                    self.startAnimating()
                }
            }
        }
    }

    private func setImage(withGIF gif: GIF) {
        animationImages = gif.images
        animationDuration = gif.durationInSec
        animationRepeatCount = gif.repeatCount
    }
}

extension UIImage {
    class func makeGIFFromCollection(name: String, repeatCount: Int = 0) -> GIF? {
        guard let path = Bundle.main.path(forResource: name, ofType: "gif") else {
            print("Cannot find a path from the file \"\(name)\"")
            return nil
        }

        let url = URL(fileURLWithPath: path)
        let data = try? Data(contentsOf: url)
        guard let d = data else {
            print("Cannot turn image named \"\(name)\" into data")
            return nil
        }

        return makeGIFFromData(data: d, repeatCount: repeatCount)
    }

    class func makeGIFFromData(data: Data, repeatCount: Int = 0) -> GIF? {
        guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
            print("Source for the image does not exist")
            return nil
        }

        let count = CGImageSourceGetCount(source)
        var images = [UIImage]()
        var duration = 0.0

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

                let delaySeconds = UIImage.delayForImageAtIndex(Int(i),
                                                                source: source)
                duration += delaySeconds
            }
        }

        return GIF(images: images, durationInSec: duration, repeatCount: repeatCount)
    }

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

        // Get dictionaries
        let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
        let gifPropertiesPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 0)
        if CFDictionaryGetValueIfPresent(cfProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque(), gifPropertiesPointer) == false {
            return delay
        }

        let gifProperties:CFDictionary = unsafeBitCast(gifPropertiesPointer.pointee, to: CFDictionary.self)

        // Get delay time
        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 ?? 0

        return delay
    }
}

class GIF: NSObject {
    let images: [UIImage]
    let durationInSec: TimeInterval
    let repeatCount: Int

    init(images: [UIImage], durationInSec: TimeInterval, repeatCount: Int = 0) {
        self.images = images
        self.durationInSec = durationInSec
        self.repeatCount = repeatCount
    }
}

使用方法:

override func viewDidLoad() {
    super.viewDidLoad()
    imageView.setGIFImage(name: "gif_file_name")
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    imageView.stopAnimating()
}

请确保将gif文件添加到项目中,而不是.xcassets文件夹中。


您的代码引起了错误: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)! - Coder ACJHP
不错的解决方案,但由于高内存消耗,很遗憾实际上并不可用。 - Ely

12

请查看此链接:

https://github.com/mayoff/uiimage-from-animated-gif/blob/master/uiimage-from-animated-gif/UIImage%2BanimatedGIF.h

并导入这两个类:UIImage+animatedGIF.h 和 UIImage+animatedGIF.m

使用以下代码:

 NSURL *urlZif = [[NSBundle mainBundle] URLForResource:@"dots64" withExtension:@"gif"];
 NSString *path=[[NSBundle mainBundle]pathForResource:@"bar180" ofType:@"gif"];
 NSURL *url=[[NSURL alloc] initFileURLWithPath:path];
 imageVw.image= [UIImage animatedImageWithAnimatedGIFURL:url];

希望这能帮到您


6

这不符合使用UIImageView的要求,但或许对你来说使用UIWebView会更简单。你考虑过使用UIWebView吗?

NSString *gifUrl = @"http://gifs.com";
NSURL *url = [NSURL URLWithString: gifUrl];
[webView loadRequest: [NSURLRequest requestWithURL:url]

如果你想的话,可以将一个HTML文件导入到Xcode项目中,并在字符串中设置根路径,而不是链接到需要互联网的URL。


3

3

我知道已经有一个答案被批准了,但是很难不想分享一下我的经验,我创建了一个嵌入式框架,可以为iOS添加Gif支持,感觉就像使用任何其他UIKit框架类一样。

这里有一个例子:

UIGifImage *gif = [[UIGifImage alloc] initWithData:imageData];
anUiImageView.image = gif;

https://github.com/ObjSal/UIGifImage/releases下载最新版。

-- Sal


1

SWIFT 3

以下是需要Swift版本的更新!

几天前,我需要做这样一件事情。根据特定的参数从服务器加载一些数据,并在此期间显示不同的“加载”gif图像。我正在寻找使用UIImageView实现它的选项,但不幸的是,我没有找到不分割.gif图像就能完成的解决方案。因此,我决定使用UIWebView来实现一个解决方案,并想要分享它:

extension UIView{
    func animateWithGIF(name: String){
        let htmlString: String =    "<!DOCTYPE html><html><head><title></title></head>" +
                                        "<body style=\"background-color: transparent;\">" +
                                            "<img src=\""+name+"\" align=\"middle\" style=\"width:100%;height:100%;\">" +
                                        "</body>" +
                                    "</html>"

        let path: NSString = Bundle.main.bundlePath as NSString
        let baseURL: URL = URL(fileURLWithPath: path as String) // to load images just specifying its name without full path

        let frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
        let gifView = UIWebView(frame: frame)

        gifView.isOpaque = false // The drawing system composites the view normally with other content.
        gifView.backgroundColor = UIColor.clear
        gifView.loadHTMLString(htmlString, baseURL: baseURL)

        var s: [UIView] = self.subviews 
        for i in 0 ..< s.count {
            if s[i].isKind(of: UIWebView.self) { s[i].removeFromSuperview() }
        }

        self.addSubview(gifView)
    }

    func animateWithGIF(url: String){
        self.animateWithGIF(name: url)
    }
} 

我为UIView创建了一个扩展,它将UIWebView作为子视图添加,并显示传递其名称的.gif图像。
现在,在我的UIViewController中,我有一个名为“loadingView”的UIView,它是我的“加载”指示器,每当我想要显示.gif图像时,我会这样做:
class ViewController: UIViewController {
    @IBOutlet var loadingView: UIView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        configureLoadingView(name: "loading.gif")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // .... some code
        // show "loading" image
        showLoadingView()
    }

    func showLoadingView(){
        loadingView.isHidden = false
    }
    func hideLoadingView(){
        loadingView.isHidden = true
    }
    func configureLoadingView(name: String){
        loadingView.animateWithGIF(name: "name")// change the image
    }
}

当我想要更改gif图像时,只需使用我的新.gif图像的名称调用函数configureLoadingView()并调用showLoadingView()hideLoadingView(),一切都正常运作!但是......如果您将图像拆分,则可以使用名为UIImage.animatedImageNamedUIImage静态方法在单行中对其进行动画处理,如下所示:imageView.image = UIImage.animatedImageNamed("imageName", duration: 1.0)。从文档中可以看出:此方法通过将一系列数字添加到name参数中提供的基本文件名来加载一系列文件。包含在动画图像中的所有图像应具有相同的大小和比例。或者,您可以使用UIImage.animatedImageWithImages方法进行操作,如下所示:
let images: [UIImage] = [UIImage(named: "imageName1")!,
                                            UIImage(named: "imageName2")!,
                                            ...,
                                            UIImage(named: "imageNameN")!]
imageView.image = UIImage.animatedImage(with: images, duration: 1.0)

来自文档:

从现有的一组图像创建并返回一个动画图像。所有包含在动画图像中的图像应该具有相同的大小和比例。


1
如果您必须从URL加载gif图像,则可以在UIWebView中的图像标签中嵌入gif。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接