表格视图中单元格内的自动布局图像。正确的布局,但只有一次向下滚动和备份?

Posted

技术标签:

【中文标题】表格视图中单元格内的自动布局图像。正确的布局,但只有一次向下滚动和备份?【英文标题】:Autolayout images inside cells in tableview. Correct layout but only once scrolling down and back up? 【发布时间】:2020-01-13 18:32:13 【问题描述】:

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

我创建了一个单元格类,它只有标签、imageView 和图像高度的 NSLayoutConstraint 的出口。我有一些异步方法来下载图像并将其设置为单元格 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()

这适用于框架外的所有单元格,但框架内单元格中的图像视图很小。只有当我向下滚动然后再次备份时,它们的大小才会正确。我该如何解决?我知道其他人也遇到过这个问题,但尝试他们的修复没有任何效果。

【问题讨论】:

我删除了我的答案,因为它似乎不是线程问题,您显示的添加代码提供了更多上下文。似乎您的约束设置不正确,或者您在单元格的初始化中正在做一些您在设置图像后也需要做的事情。 你用的是故事板对吗? 是的,使用带有 tableview IBOutlet 的情节提要 我正在为你编写一些代码,大概给我一个小时吧。只要确保它适合你。 对于调整单元格大小,您是否查看过estimatedHeightForRowAtheightForRowAt 【参考方案1】:

我不得不重新创建问题以了解发生了什么。基本上你需要重新加载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()
      

现在,当照片下载完成后,您可以使用以下命令通知视图控制器重新加载表格视图,

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() 

viewController.swift(点击查看完整代码) 我只是在这里给出代码的亮点。

//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
                   
         



    

【讨论】:

以此为基础,重新加载整个表格视图而不是视图中的单元格更容易。 谢谢!我发现了问题,我应该在显示它们之前加载所有图像,这样它们就会立即正确布局! 假设你没有下载很多图片呢?如果您有太多,首先加载所有这些可能对某些用户来说需要一段时间。请记住,这是您可能拥有/想要改变的东西。 只加载 10 个小图像,更多的会在表格视图中加载约 75%。另外,我只是在加载最初的 10 张图像时添加了一些骨架视图,但除非您的互联网速度低于 1mbps,否则您将永远看不到它们。 :)

以上是关于表格视图中单元格内的自动布局图像。正确的布局,但只有一次向下滚动和备份?的主要内容,如果未能解决你的问题,请参考以下文章

使用自动布局表格视图时如何增加表格视图单元格中的标签高度(取决于文本)?

使用自动布局进行编辑时在表格视图中调整子视图的大小

iOS - 表格视图单元格中的自动布局问题

在表格视图单元格内设置集合视图约束的正确方法

表视图单元格仅在屏幕外时自动布局

带有图像和文本字段的自动布局表格单元格?