有时候我们需要在View中显示Gif图片,需要借助GifImageViewController
- 把图片拷贝到工程

- 在SwiftUI中 调用GifImageView即可。
struct LoadingView: View {
@State var gifName: String = "Loading"
var body: some View {
VStack(alignment: .center, spacing: 0){
GifImageView(imageName: self.$gifName)
- GifImageView代码 注意修改gifImageWithName 图片路径。
struct GifImageView: UIViewControllerRepresentable{
@Binding var imageName: String
func makeUIViewController(context: Context) -> GifImageViewController {
let picker = GifImageViewController(imageName: self.imageName)
return picker
}
func updateUIViewController(_ uiViewController: GifImageViewController,context: UIViewControllerRepresentableContext<GifImageView>) {
uiViewController.imageView.removeFromSuperview()
uiViewController.imageName = imageName
uiViewController.viewDidLoad()
}
}
class GifImageViewController: UIViewController {
// lazy var imageView: UIImageView = {
var imageView: UIImageView = UIImageView()
// return imageView
// }()
fileprivate var imageName: String = ""
convenience init(imageName: String) {
self.init()
self.imageName = imageName
}
override func viewDidLoad() {
super.viewDidLoad()
/************************ Load GIF image Using Name ********************/
// print(self.imageName)
let jeremyGif = UIImage.gifImageWithName(self.imageName)
imageView = UIImageView(image: jeremyGif)
// imageView.frame = self.view.bounds
imageView.frame = CGRect(x: 0, y: 0, width: 42, height: 42)
view.addSubview(imageView)
/************************ Load GIF image Using Data ********************/
// 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)
//
// /************************ Load GIF image URL **************************/
//
// 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)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension UIImage {
public class func gifImageWithData(_ data: Data) -> UIImage? {
guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
print("image doesn't exist")
return nil
}
return UIImage.animatedImageWithSource(source)
}
public class func gifImageWithURL(_ gifUrl:String) -> UIImage? {
guard let bundleURL:URL = URL(string: gifUrl)
else {
print("image named \"\(gifUrl)\" doesn't exist")
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL) else {
print("image named \"\(gifUrl)\" into NSData")
return nil
}
return gifImageWithData(imageData)
}
// ※subdirectory需要修改
public class func gifImageWithName(_ name: String) -> UIImage? {
guard let bundleURL = Bundle.main
.url(forResource: name, withExtension: "gif", subdirectory: "Music") else {
print("SwiftGif: This image named \"\(name)\" does not exist")
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL) else {
print("SwiftGif: Cannot turn image named \"\(name)\" into NSData")
return nil
}
return gifImageWithData(imageData)
}
class func delayForImageAtIndex(_ index: Int, source: CGImageSource!) -> Double {
var delay = 0.03
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.03 {
delay = 0.03
}
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(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(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(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
}
}