动态单元高度问题

Posted

技术标签:

【中文标题】动态单元高度问题【英文标题】:Dynamic Cell Height Issue 【发布时间】:2017-08-20 04:20:37 【问题描述】:

我有一个动态单元格,两个图像之间有一个标签,每个单元格底部图像下方有两个按钮。标签的大小取决于标签中的行数,可以是任何值。我在cellForRowAt indexPath 中获得了标签的文本。在我的viewDidLoad() 中,我已经通过使用这个设置了一个动态单元格:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 265

问题:标签超过1行时,单元格的高度大小不变。它只有在两种情况下才有机会获得正确的大小:1)当我刷新表格时。 2)当我向下滚动损坏的单元格不在视图中时,然后当我向上滚动时,损坏的单元格位于正确的位置。

我尝试过的:经过数小时的尝试后,有许多消息来源说 2 个相同的事情:1) 确保所有项目对其所有项目都有限制双方(我这样做了,同样的问题发生了)。 2)唯一的另一个说使用UITableViewAutomaticDimensionestimatedRowHeight(我有)。

我该如何解决这个问题或者我错过了什么?

编辑:在得到它是哪种类型的单元格后,我在cellForRowAt indexPath 中调用标签的文本(我有 3 个,它们都做不同的事情)。代码如下:

    func loadNews()         
            //start finding followers
            let followQuery = PFQuery(className: "Follow")
            followQuery.whereKey("follower", equalTo: PFUser.current()?.objectId! ?? String())
            followQuery.findObjectsInBackground  (objects, error) in
                if error == nil 

                    self.followArray.removeAll(keepingCapacity: false)

                    //find users we are following
                    for object in objects!
                        self.followArray.append(object.object(forKey: "following") as! String)
                    
                    self.followArray.append(PFUser.current()?.objectId! ?? String()) //so we can see our own post


                    //getting related news post
                    let newsQuery = PFQuery(className: "News")
                    newsQuery.whereKey("user", containedIn: self.followArray) //find this info from who we're following
                    newsQuery.limit = 30
                    newsQuery.addDescendingOrder("createdAt")
                    newsQuery.findObjectsInBackground(block:  (objects, error) in
                        if error == nil      
                            //clean up
                            self.newsTypeArray.removeAll(keepingCapacity: false)
                            self.animalArray.removeAll(keepingCapacity: false)
                            self.newsDateArray.removeAll(keepingCapacity: false)

                            for object in objects!                             
                                self.newsTypeArray.append(object.value(forKey: "type") as! String) //get what type (animal / human / elements)

                                self.animalArray.append(object.value(forKey: "id") as! String) //get the object ID that corresponds to different class with its info
                                self.newsDateArray.append(object.createdAt) //get when posted
                            
                            self.tableView.reloadData()
                         else 
                            print(error?.localizedDescription ?? String())
                        
                    )
                 else 
                    print(error?.localizedDescription ?? String())
                
               
        



        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let type = newsTypeArray[indexPath.row]

    if type == "element" 
      //fills cell just like animal one
     else if type == "human" 
      //fills cell just like animal one

     else  //its an animal cell

                            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! AnimalCell
                            let query = query(className: "Animals")
                            query.whereKey("objectId", equalTo: animalArray[indexPath.row])
                            query.limit = 1
                            query.findObjectsInBackground(block:  (objects, error) in
                                if error == nil                             
                                    for object in objects! 

                                        let caption = (object.object(forKey: "caption") as! String)
                                        cell.captionLabel.text = caption

                                                                   
                                 else 
                                    print(error?.localizedDescription ?? String())
                                
                            )
           return cell
        
    

【问题讨论】:

你把标签 numberOfLines 改成 0 了吗? 标签行数为0 @Imad Ali 显示您的自定义单元格 请参考here,如果还有疑问可以询问。 @fphelp 你能添加你的 cellForRowAt 方法吗?特别是如果您正在执行任何类型的调度或网络调用来获取标签文本? 【参考方案1】:

1.检查您是否在单元格中使用了正确的constraints

2。实现这些UITableViewDelegate 方法:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat

    return UITableViewAutomaticDimension


func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat

    return 265

删除这两行:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 265

截图:

1.查看层次结构:Image1 -> Label -> Image2 -> Button1 -> Button2

2。输出

如果它不起作用:

在您的自定义UITableViewCell 中提供preferredMaxLayoutWidthUILabel,即

override func awakeFromNib()

    super.awakeFromNib()
    self.label.preferredMaxLayoutWidth = UIScreen.main.bounds.width //Provide here the calculated width of your label

UITableViewDataSource方法:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

    return 2


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableCell
    if indexPath.row == 0
    
        cell.label.text = "When the label is more than 1 line, the size of the height of the cell does not change."
    
    else
    
        cell.label.text = "When the label is more than 1 line, the size of the height of the cell does not change. It only chances to the correct size in two instances: 1) When I refresh the table. 2) when I scroll down where the broken cell is not in the view then when I scroll back up the broken cell is at the correct position."
    
    return cell

【讨论】:

遗憾的是得到了同样的结果 我在cellForRowAt indexPath 中获得单元格标签的文本这一事实是否与问题有关? 不,完全没问题。我也会添加 UITableViewDataSource 的代码,以便您有更好的想法。 您使用的是哪个 ios 版本? 我在 Xcode 模拟器上运行 iOS 10.3,在 iPhone 6s 上运行 iOS 10.3。并且在两种设备上都收到相同的结果【参考方案2】:

这听起来像是在加载初始表数据后设置标签的内容(可能使用后台方法从网络获取值?)。

如果是这种情况,您可以使用UITableView.reloadRows(at:with:) 方法重新加载表格中的那个单元格。见:https://developer.apple.com/documentation/uikit/uitableview/1614935-reloadrows

例如:tableView.reloadRows(at: [indexPathToCell], with: .automatic)

【讨论】:

在标签的文本被收集之后,我在cellForRowAt 中实现了tableView.reloadRows,并且由于某种原因它开始重新加载我的所有行。我正在使用解析,我只是查询标签的文本并设置label.text = \\what I get from server没什么特别的 那是你的问题。 Parse 正在执行网络调用,您在 cellForRowAt 方法返回后的某个时间点设置标签的值。所以你需要在那之后触发重新加载。在label.text = ... 行之后添加DispatchQueue.main.async tableView.reloadRows(at: [indexPathToCell], with: .none) @fphelp 注意:根据标签文本更改的频率,您可能最好在视图出现之前的某个时间通过解析加载值,并将其缓存。不需要每次单元格出现在屏幕上时都使用 Parse,除非数据可以经常更改。 我尝试了DispatchQueue.main.async tableView.reloadRows(at: [indexPathToCell], with: .none) ,它一遍又一遍地重新加载单元格。我用let index = IndexPath(row: indexPath.row, section: 0) 替换了你的“indexPathToCell” 我想再次加载文本标签,但这很复杂,因为我有 2 个其他单元格可以进入 tableview 执行与我遇到问题的单元格不同的事情。因此,我将来自不同类的类型及其对应的 objectId 加载到数组中,然后在每个单元格中加载它们的内容。 如果有可能的解决方案,我该如何解决?

以上是关于动态单元高度问题的主要内容,如果未能解决你的问题,请参考以下文章

动态单元高度问题

单元格中的标签高度不会动态改变高度

动态单元高度有时不反映

动态 UITableView 单元格高度的问题

如何根据动态高度单元格设置 UITableView 的高度约束?

使用自定义集合视图布局快速配置动态单元格高度