Swift 在tableview中的单元格内自动布局图像。是否布局正确,但只向下和向上滚动一次?

Swift 在tableview中的单元格内自动布局图像。是否布局正确,但只向下和向上滚动一次?,swift,uitableview,asynchronous,uiimageview,Swift,Uitableview,Asynchronous,Uiimageview,我正在尝试使用自动调整图像大小的tableview单元格。基本上,我希望单元格中的图像宽度始终相同,高度根据图像的纵横比而变化 我创建了一个cell类,它只有标签、imageView和图像高度的NSLayoutConstraint的输出。我有一些异步方法来下载图像并将其设置为cell imageView的图像。然后调用完成句柄,我运行以下代码将高度约束调整为正确的高度: cell.cellPhoto.loadImageFromURL(url: photos[indexPath.row].thum

我正在尝试使用自动调整图像大小的tableview单元格。基本上,我希望单元格中的图像宽度始终相同,高度根据图像的纵横比而变化

我创建了一个cell类,它只有标签、imageView和图像高度的NSLayoutConstraint的输出。我有一些异步方法来下载图像并将其设置为cell imageView的图像。然后调用完成句柄,我运行以下代码将高度约束调整为正确的高度:

cell.cellPhoto.loadImageFromURL(url: photos[indexPath.row].thumbnailURL, completion: {
            // Set imageView height to the width
            let imageSize = cell.cellPhoto.image?.size
            let maxHeight = ((self.tableView.frame.width-30.0)*imageSize!.height) / imageSize!.width
            cell.cellPhotoHeight.constant = maxHeight
            cell.layoutIfNeeded()
        })
        return cell
这是我编写的UIImageView扩展,用于加载图像:

func loadImageFromURL(url: String, completion: @escaping () -> Void) {
        let url = URL(string: url)
        makeDataRequest(url: url!, completion: { data in
            DispatchQueue.main.async {
                self.image = UIImage(data: data!)
                completion()
            }
        })
    }
以及它调用的makeDataRequest函数:

func makeDataRequest(url: URL, completion: @escaping (Data?) -> Void) {
    let session = URLSession.shared

    let task = session.dataTask(with: url, completionHandler: { data, response, error in
        if error == nil {
            let response = response as? HTTPURLResponse
            switch response?.statusCode {
                case 200:
                    completion(data)
                case 404:
                    print("Invalid URL for request")
                default:
                    print("Something else went wrong in the data request")
            }
        } else {
            print(error?.localizedDescription ?? "Error")
        }
    })

    task.resume()
}

这适用于帧外的所有单元格,但帧中单元格中的ImageView较小。只有当我向下滚动然后再次向上滚动时,它们的大小才正确。我该如何解决这个问题?我知道其他人也有过这个问题,但尝试他们的修复却没有任何效果。

我不得不重新创建这个问题,以了解到底发生了什么。基本上,您需要重新加载tableview。我会在图片下载完成后这样做

在具有表视图变量的视图控制器中,将其添加到
viewDidLoad()
函数中

   override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self

        //Create a notification so we can update the list from anywhere in the app. Good if you are calling this from an other class.
         NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "loadList"), object: nil)

    }

   //This function updates the cells in the table view
   @objc func loadList(){
          //load data here
          self.tableView.reloadData()
      }
现在,下载完照片后,可以使用以下命令通知viewcontroller重新加载表视图:

func loadImageFromURL(url: String, completion: @escaping () -> Void) {
        let url = URL(string: url)
        makeDataRequest(url: url!, completion: { data in
            DispatchQueue.main.async {
                self.image = UIImage(data: data!)
                completion()
                //This isn't the best way to do this as, if you have 25+ pictures,
                //the list will pretty much freeze up every time the list has to be reloaded.
                //What you could do is have a flag to check if the first 'n' number of cells 
                //have been loaded, and if so then don't reload the tableview.

                //Basically what I'm saying is, if the cells are off the screen who cares.
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadList"), object: nil)
            }
        })
    }
下面是我为更好地实现异步所做的一些事情,请参见下文。

我的代码如下所示,我没有像你那样做调整比例的事情,但同样的想法也适用。这是重新加载表视图的方式。另外,我个人不喜欢写我自己的下载代码,包括状态代码和所有东西。这一点都不好玩,为什么要在别人做的时候重新发明轮子呢

Podfile

pod 'SDWebImage',  '~> 5.0' 
mCell.swift

class mCell: UITableViewCell {
    //This keeps track to see if the cell has been already resized. This is only needed once.
    var flag = false
    @IBOutlet weak var cellLabel: UILabel!
    @IBOutlet weak var cell_IV: UIImageView!

    override func awakeFromNib() { super.awakeFromNib() }
}
(单击查看完整代码) 我将在这里重点介绍代码

//Set the image based on a url
//Remember this is all done with Async...In the backgorund, on a custom thread.
mCell.cell_IV.sd_setImage(with: URL(string: ViewController.cell_pic_url[row])) { (image, error, cache, urls) in
    // If failed to load image
    if (error != nil) {
        //Set to defult
         mCell.cell_IV.image = UIImage(named: "redx.png")
     }
    //Else we got the image from the web.
    else {
         //Set the cell image to the one we downloaded
         mCell.cell_IV.image = image

         //This is a flag to reload the tableview once the image is done downloading. I set a var in the cell class, this is to make sure the this is ONLY CALLED once. Otherwise the app will get stuck in an infinite loop.
         if (mCell.flag != true){
             DispatchQueue.main.asyncAfter(deadline: .now() + 0.025){ //Nothing wrong with a little lag.
                      NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadList"), object: nil)
                      mCell.flag = true
                   }
         }



    }
}

我删除了我的答案,因为它似乎不是一个线程问题,因为您添加的代码提供了更多的上下文。似乎您的约束设置不正确,或者您在单元格初始化中执行了一些设置图像后也需要执行的操作。您使用的是情节提要,对吗?是的,将情节提要与tableview IBOutletI一起使用。我正在为您编写一些代码,可能需要一个小时。只是要确保它对您有效。此外,为了调整单元格的大小,您已经查看了
estimatedHeightForRowAt
heightForRowAt
?在此基础上,可以更轻松地重新加载整个表视图,而不是视图中的单元格。谢谢!我解决了这个问题,我应该在显示它们之前加载所有图像,这样它们就可以立即获得正确的布局!假设你没有下载很多图片?如果您有太多,那么对于某些用户来说,首先加载所有这些文件可能需要一段时间。请记住,这是您可能已经/想要在将来更改的内容。仅加载10个小图像,更多图像将在表视图中加载大约75%。另外,在加载最初的10幅图像时,我刚刚添加了一些骨架视图,但除非您的互联网速度低于1mbps,否则您将永远看不到它们。:)