创建加载图像/ activity 指示器,直到图像显示在 swift 中的屏幕上

create a loading image/ activity indicator, until the image is shown in the screen in swift

我想在从网站下载图像时在屏幕上显示一个 activity 指示器 url 然后在 images.image 中显示这是我下面的代码。每次我下载图像时,它都会立即打印状态,并且 activity 指示器永远不会出现。一直在网上搜索,但我还是不明白。请帮忙

 let mygroup = DispatchGroup()
 var activityIndicator = UIActivityIndicatorView()

func downloadpic(sender:UIButton){
    let catPictureURL = URL(string: addr)!

    // Creating a session object with the default configuration.
    // You can read more about it here https://developer.apple.com/reference/foundation/urlsessionconfiguration
    let session = URLSession(configuration: .default)

    // Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data.

    let downloadPicTask = session.dataTask(with: catPictureURL) { (data, response, error) in
        // The download has finished.
        if let e = error {
            print("Error downloading cat picture: \(e)")
        } else {
            // No errors found.
            // It would be weird if we didn't have a response, so check for that too.
            if let res = response as? HTTPURLResponse {
                // put loading screen here
                self.activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
                self.activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
                self.activityIndicator.startAnimating()
                self.mygroup.enter()
                print("downloading image")
                print("Downloaded cat picture with response code \(res.statusCode)")
                if let imageData = data {
                    // Finally convert that Data into an image and do what you wish with it.
                     self.images.image = UIImage(data: imageData)
                        self.mygroup.leave()
                        print("image already downloaded")
                        self.activityIndicator.stopAnimating()
                        self.activityIndicator.hidesWhenStopped = true


                    // Do something with your image.
                } else {
                    print("Couldn't get image: Image is nil")
                }
            } else {
                print("Couldn't get response code for some reason")
            }
        }
    }

    downloadPicTask.resume()
}

您遇到了这个问题,因为:

  1. 您没有将 activityIndicator 添加到任何视图
  2. 您在 completionHandler 块中配置了 activityIndicator

让我们在 activityIndicator 中配置 viewDidLoad() 方法:

self.activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
self.activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
self.activityIndicator.hidesWhenStopped = true

view.addSubview(self.activityIndicator)

并在恢复 dataTask

之前开始对其进行动画处理
self.activityIndicator.startAnimating()

然后,停止在 completionHandler

self.activityIndicator.stopAnimating()

最终代码:

let mygroup = DispatchGroup()
var activityIndicator = UIActivityIndicatorView()

override func viewDidLoad() {
    super.viewDidLoad()

    self.activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
    self.activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
    self.activityIndicator.hidesWhenStopped = true

    view.addSubview(self.activityIndicator)
}

func downloadpic(sender: UIButton) {
    let catPictureURL = URL(string: addr)!

    // Creating a session object with the default configuration.
    // You can read more about it here https://developer.apple.com/reference/foundation/urlsessionconfiguration
    let session = URLSession(configuration: .default)

    // Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data.

    self.activityIndicator.startAnimating()

    let downloadPicTask = session.dataTask(with: catPictureURL) { (data, response, error) in
        // The download has finished.
        if let e = error {
            print("Error downloading cat picture: \(e)")
        } else {
            // No errors found.
            // It would be weird if we didn't have a response, so check for that too.
            if let res = response as? HTTPURLResponse {
                // put loading screen here

                self.mygroup.enter()
                print("downloading image")
                print("Downloaded cat picture with response code \(res.statusCode)")
                if let imageData = data {
                    // Finally convert that Data into an image and do what you wish with it.
                    self.images.image = UIImage(data: imageData)
                    self.mygroup.leave()
                    print("image already downloaded")
                    self.activityIndicator.stopAnimating()

                    // Do something with your image.
                } else {
                    print("Couldn't get image: Image is nil")
                }
            } else {
                print("Couldn't get response code for some reason")
            }
        }
    }

    downloadPicTask.resume()
}

结果!

我推荐你使用像 AlamofireImage 这样的库,并在 UIImageView 中选择自定义 class。

自定义 Class UIImageView:

import Foundation
import UIKit
import AlamofireImage

class CustomImageView: UIImageView {

    func ImageViewLoading(mediaUrl: String) {
        guard let url = URL(string: mediaUrl) else { return }
        let activityIndicator = self.activityIndicator
        DispatchQueue.main.async {
            activityIndicator.startAnimating()
        }
        self.af.setImage(
            withURL: url,
            placeholderImage: nil,
            filter: nil,
            completion: { response in
                DispatchQueue.main.async {
                    activityIndicator.stopAnimating()
                    activityIndicator.removeFromSuperview()
                }
            }
        )
    }

    private var activityIndicator: UIActivityIndicatorView {
        let activityIndicator = UIActivityIndicatorView()
        activityIndicator.hidesWhenStopped = true
        activityIndicator.color = UIColor.black
        self.addSubview(activityIndicator)

        activityIndicator.translatesAutoresizingMaskIntoConstraints = false

        let centerX = NSLayoutConstraint(item: self,
                                         attribute: .centerX,
                                         relatedBy: .equal,
                                         toItem: activityIndicator,
                                         attribute: .centerX,
                                         multiplier: 1,
                                         constant: 0)
        let centerY = NSLayoutConstraint(item: self,
                                         attribute: .centerY,
                                         relatedBy: .equal,
                                         toItem: activityIndicator,
                                         attribute: .centerY,
                                         multiplier: 1,
                                         constant: 0)
        self.addConstraints([centerX, centerY])
        return activityIndicator
    }

}

将此 class 用于您的 UIImageView:

@IBOutlet weak var photoImageViewWithLoading: CustomImageView!

photoImageViewWithLoading.ImageViewLoading(mediaUrl: mediaUrl!)

当您从 url 加载图像时,UIImageView 将显示活动指示器

我这个回答对你有帮助。

注:我用的是Swift5

我写了一个使用 SDWebImage 的扩展。以下是我的代码,并提供了良好的用户体验。

import SDWebImage

extension UIImageView {    
    func imageURL(_ url: String) {
        let activityIndicator = UIActivityIndicatorView(style: .gray)
        activityIndicator.frame = CGRect(x: 0, y: 0, width: 64, height: 64)
        activityIndicator.hidesWhenStopped = true
        activityIndicator.startAnimating()
        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        
        activityIndicator.center = CGPoint(x: self.frame.size.width  / 2, y: self.frame.size.height / 2)
        
        self.addSubview(activityIndicator)
        
        //self.sd_setImage(with: URL(string: url), placeholderImage: UIImage(named: "placeholder.png"))
        self.sd_setImage(with: URL(string: url)) { (image, error, cacheType, url) in
            activityIndicator.stopAnimating()
        }
    }
}