【问题标题】:how to run activity indicator until download image ?如何在下载图像之前运行活动指示器?
【发布时间】:2026-02-08 03:00:01
【问题描述】:

在图像下载之前,我想启动活动指示器。

这是我使用 url 的图片下载功能

extension UIImageView {

func downloadImage(from url : String){

    let urlRequest = URLRequest(url: URL(string: url)!)
    let task = URLSession.shared.dataTask(with: urlRequest){(data,response,error)in

        if error != nil {

            print("error...")

        }

        DispatchQueue.main.async {
            self.image = UIImage(data:data!)
        }
    }

    task.resume()
}

我的问题是我该怎么做? (对不起我的英语不好)

【问题讨论】:

  • sd_webimages 库是下载图像的最佳方式。它也支持指标。
  • 谢谢。这是完美的工作! :D
  • 好吧,如果我的照片为零,我想展示我自己的形象。那么我怎么能用 sd_webimages 做到这一点呢?
  • 您应该尝试 sd_webimage initilizer 与 PlaceHolder 并将您的图像作为 placeHolder

标签: ios swift indicator activity-indicator


【解决方案1】:

您可以在方法中传递一个闭包,该闭包将在下载图像后执行

extension UIImageView {

  func downloadImage(from url : String, completion: ((_ errorMessage: String?) -> Void)?){

    let urlRequest = URLRequest(url: URL(string: url)!)
    let task = URLSession.shared.dataTask(with: urlRequest){ (data,response,error) in

      if error != nil {
        completion?("error...")
      }

      DispatchQueue.main.async {
        self.image = UIImage(data:data!)
        completion?(nil)
      }
    }

    task.resume()
  }
}

在你的 ViewController 中

activityIndicator.startAnimating()
imageView.downloadImage(from: "...") { (err) in
  if err != nil {
    // error handler
  }
  self.activityIndicator.stopAnimating()
}

【讨论】:

    【解决方案2】:

    你可以试试下面的方法

    extension UIImageView {
    
      func downloadImage(from url : String){
        self.activityIndicator.startAnimating()
        let urlRequest = URLRequest(url: URL(string: url)!)
        let task = URLSession.shared.dataTask(with: urlRequest){(data,response,error)in
          if error != nil {
            DispatchQueue.main.async {
              self.activityIndicator.stopAnimating()
            }
            print("error...")
          }
          else {
            DispatchQueue.main.async {
              self.activityIndicator.stopAnimating()
              self.image = UIImage(data:data!)
            }
          }
        }
        task.resume()
      }
    
      fileprivate var activityIndicator: UIActivityIndicatorView {
        get {
          let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
          activityIndicator.hidesWhenStopped = true
          activityIndicator.center = CGPoint(x:self.frame.width/2,
                                         y: self.frame.height/2)
          activityIndicator.stopAnimating()
          self.addSubview(activityIndicator)
          return activityIndicator
        }
      }
    }
    

    【讨论】:

    • 它正在工作,但它没有停止 =D 我怎样才能停止这个?
    • 它应该可以工作,当你提到不停止时,你能更具体一点,显示图像但活动指示器保持动画?
    【解决方案3】:

    这是对@Idindu 答案的改进,因为我使用他的答案并发现activityIndicator 存在一些问题。

    主要问题是activityIndicator即使图片已经显示也不会停止,我搜索了一下发现是因为每次调用它都会得到一个全新的实例,这就是为什么activityIndicator.stopAnimating()没用。

    接下来是activityIndicator的位置并不总是imageView的中心,我找到了更好的方法here

    所以这是我使用的最终版本:

    fileprivate var activityIndicator: UIActivityIndicatorView {
    get {
    
        if let indicator = self.subviews.first(where: { $0 is UIActivityIndicatorView }) as? UIActivityIndicatorView {
            print("image view already contains activity indicator")
            return indicator
        }
    
        let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
        activityIndicator.hidesWhenStopped = true
        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
      }
    }
    

    【讨论】:

      【解决方案4】:

      这是我加载图像的方式

      if(activityList.banner != ""){
          dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
          let fileManager = NSFileManager.defaultManager()
      
          let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
          let pathSplit = activityList.banner.characters.split{$0 == "/"}.map(String.init)
          let getImagePath = (paths as NSString).stringByAppendingPathComponent("\(pathSplit[pathSplit.count-1])")
          if (fileManager.fileExistsAtPath(getImagePath)){ // if I already download the image before I opened from the folder
              func display_image2(){
                  activityImageView.image = UIImage(contentsOfFile: getImagePath)
                  activityImageView.image = activityImageView.image?.alpha(0.7)
                  activityIndicator.hidden = true
                  //iconImageView.hidden = true
              }
              dispatch_async(dispatch_get_main_queue(), display_image2)
          }else{ //in another case I download the image from server
              let url:String = "\(Constants().mainURL)/imagecache/activity_preview/" + activityList.banner
              let imgURL: NSURL = NSURL(string: url)!
              let request: NSURLRequest = NSURLRequest(URL: imgURL)
      
              let session = NSURLSession.sharedSession()
              let task = session.dataTaskWithRequest(request){
                  (data, response, error) -> Void in
      
                  if (error == nil && data != nil){
                      func display_image(){
                          activityImageView.image = UIImage(data: data!)
      
                          if let data = UIImageJPEGRepresentation(UIImage(data: data!)!, 0.8) {
                              data.writeToFile(getImagePath, atomically: true)
                          }
                              activityIndicator.hidden = true
                          //iconImageView.hidden = true
                          activityImageView.image = activityImageView.image?.alpha(0.7)
      
                      }
                      dispatch_async(dispatch_get_main_queue(), display_image)
                  }
      
              }
      
              task.resume()
          }
          })
      }
      

      【讨论】: