Swift - 从 UICollectionViewCell 内的视图中删除约束

Posted

技术标签:

【中文标题】Swift - 从 UICollectionViewCell 内的视图中删除约束【英文标题】:Swift - Remove constraints from a view inside a UICollectionViewCell 【发布时间】:2020-07-20 22:14:34 【问题描述】:

我以编程方式在自定义 UICollectionViewCell 内的视图中添加了一些约束,但我注意到当一个单元格被重用时,可能会重新添加约束。

这是正在记录的内容:

> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
> to catch this in the debugger. The methods in the
> UIConstraintBasedLayoutDebugging category on UIView listed in
> <UIKitCore/UIView.h> may also be helpful. 2020-07-21
> 01:00:10.466637+0300 AutoLayout Message Cells[5227:336361]
> [LayoutConstraints] Unable to simultaneously satisfy constraints.
>   Probably at least one of the constraints in the following list is one
> you don't want.   Try this:       (1) look at each constraint and try to
> figure out which you don't expect;        (2) find the code that added the
> unwanted constraint or constraints and fix it.  (
>     "<NSLayoutConstraint:0x600000435090 AutoLayout_Message_Cells.MessageCollectionViewCell:0x7fbd76e24670.height
> == UIView:0x7fbd76e291b0.height   (active)>",
>     "<NSLayoutConstraint:0x6000004350e0 V:|-(8)-[UILabel:0x7fbd76e29510'UOA']   (active, names:
> '|':UIView:0x7fbd76e291b0 )>",
>     "<NSLayoutConstraint:0x6000004351d0 UILabel:0x7fbd76e29510'UOA'.height == 30   (active)>",
>     "<NSLayoutConstraint:0x600000435220 V:[UILabel:0x7fbd76e29510'UOA']-(-12)-[UILabel:0x7fbd76e29790'2h']  
> (active)>",
>     "<NSLayoutConstraint:0x600000435310 UILabel:0x7fbd76e29790'2h'.height == 30   (active)>",
>     "<NSLayoutConstraint:0x6000004353b0 V:[UILabel:0x7fbd76e29790'2h']-(16)-[UITextView:0x7fbd7805b200'Lorem
> ipsum dolor sit ame...']   (active)>",
>     "<NSLayoutConstraint:0x600000435400 UITextView:0x7fbd7805b200'Lorem ipsum dolor sit ame...'.bottom ==
> UIView:0x7fbd76e291b0.bottom - 1   (active)>",
>     "<NSLayoutConstraint:0x60000042a990 'UIView-Encapsulated-Layout-Height'
> AutoLayout_Message_Cells.MessageCollectionViewCell:0x7fbd76e24670.height
> == 50   (active)>" )

这是我手机的代码:

import UIKit

class MessageCollectionViewCell: UICollectionViewCell 
    @IBOutlet var textView: UITextView!
    @IBOutlet var schoolLabel: UILabel!
    @IBOutlet var dateLabel: UILabel!
    
    override func awakeFromNib() 
        super.awakeFromNib()
        setupConstraints()
    
    
    fileprivate func setupConstraints() 
        setupCellConstraints()
        setupSchoolLabelConstraints()
        setupDateLabelConstraints()
        setupTextViewConstraints()
    
    
    fileprivate func setupCellConstraints() 
        self.contentView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            self.contentView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - (self.frame.origin.x * 2))
        ])
        
        NSLayoutConstraint.activate([
            self.widthAnchor.constraint(equalTo: self.contentView.widthAnchor),
            self.heightAnchor.constraint(equalTo: self.contentView.heightAnchor)
        ])
    
    
    fileprivate func setupSchoolLabelConstraints() 
        schoolLabel.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            schoolLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 8),
            schoolLabel.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 8),
            schoolLabel.trailingAnchor.constraint(equalTo: self.contentView.centerXAnchor, constant: 60),
            schoolLabel.heightAnchor.constraint(equalToConstant: 30)
        ])
    
    
    fileprivate func setupDateLabelConstraints() 
        dateLabel.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            dateLabel.topAnchor.constraint(equalTo: schoolLabel.bottomAnchor, constant: -12),
            dateLabel.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 8),
            dateLabel.trailingAnchor.constraint(equalTo: self.contentView.centerXAnchor, constant: 60),
            dateLabel.heightAnchor.constraint(equalToConstant: 30)
        ])
    
    
    fileprivate func setupTextViewConstraints() 
        textView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            textView.topAnchor.constraint(equalTo: dateLabel.bottomAnchor, constant: 16),
            textView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -1),
            textView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 8),
            textView.trailingAnchor.constraint(lessThanOrEqualTo: self.contentView.centerXAnchor, constant: 60)
        ])
    

有没有办法在重新添加之前清除所有约束?

【问题讨论】:

这是唯一的出路?我不认为保留对约束的引用是最好的...... 好的,我刚刚查看了您的约束,它们本身就是错误的。 我刚刚开始使用 AutoLayout,所以您可能是对的!我做错了什么? 只需在storyboard中配置约束即可。并且不要约束单元格或内容视图。删除所有代码。 我正在限制单元格的宽度,以便它可以根据textViews 文本具有动态高度 【参考方案1】:

我也以编程方式而不是在情节提要中使用约束。您遇到的问题是某些约束不能共存。

例如在代码中我没有看到:

>     "<NSLayoutConstraint:0x60000042a990 'UIView-Encapsulated-Layout-Height'
> AutoLayout_Message_Cells.MessageCollectionViewCell:0x7fbd76e24670.height
> == 50   (active)>" )

某处(可能在故事板中?)您给出的高度为 50,但是:

单元格与 contentView 的高度相同:

self.heightAnchor.constraint(equalTo: self.contentView.heightAnchor)

在您提供的单元格中:

        schoolLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 8),
....
        schoolLabel.heightAnchor.constraint(equalToConstant: 30)

所以我们有 8 个形式的内容顶部 + 30 个高度 (38),那么:

        dateLabel.topAnchor.constraint(equalTo: schoolLabel.bottomAnchor, constant: -12),
....
        dateLabel.heightAnchor.constraint(equalToConstant: 30)

您返回 12,然后再次返回 30 (38 - 12 + 30 = 56) 的高度。 我们超出了 50 个单元格,再加上您添加的文本:

        textView.topAnchor.constraint(equalTo: dateLabel.bottomAnchor, constant: 16),
        textView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -1)

其高度将导致负数(textView 顶部为 56 + 16 = 72,但底部为 50(我们看不到的约束)- 1 = 49 --> 它的高度为 -23

【讨论】:

那我该怎么办?我检查了,我没有为项目中任何地方的单元格指定高度 50 我应该从标签中删除高度并运行它,检查会发生什么。消息说'AutoLayout_Message_Cells',所以它可能有点奇怪..就像你决定在视图中有X行并创建它们它创建50高度的约束。或者您可以为内容视图指定高度 80(或准确地说是 72),然后查看错误是否再次出现。

以上是关于Swift - 从 UICollectionViewCell 内的视图中删除约束的主要内容,如果未能解决你的问题,请参考以下文章

Swift5 踩过的坑和奇怪的API笔记

Swift5 踩过的坑和奇怪的API笔记

如何将数据从 uitableviewcontroller 发送到 uitableviewcell

快速检测从照片库中删除的图像

UICollectionView reloadSection 不会从视图层次结构中删除旧视图

从 UICollectionView 宽度设置 Ancor 约束中的宽度