带有 centerXAnchor 集的 UITableViewCell 自动布局问题

UITableViewCell auto-layout issue with centerXAnchor set

我正在尝试构建消息传递界面并遇到了这个问题。由于这是消息传递应用程序,消息气泡要么对齐前导,要么对齐尾随。我想做这种事情,创建一个名为 bubbleView 的子视图,它将使用一个名为 bubbleViewCenterXConstraintValue.

的计算变量自行对齐
override var frame: CGRect {
    didSet {
        print(frame, bubbleView.frame)
        self.setNeedsLayout()
    }
}

private var bubbleViewCenterXConstraintValue: CGFloat {
    print(UIScreen.main.bounds.width, contentView.frame.width, bubbleView.frame.width, ((UIScreen.main.bounds.width - bubbleView.bounds.width) / 2))
    return ((UIScreen.main.bounds.width - bubbleView.bounds.width) / 2)
}

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    
    backgroundColor = .clear
    contentView.backgroundColor = .systemTeal
    
    bubbleView.addSubviews(messageLabel, hourLabel)
    
    messageLabel.leadingAnchor.constraint(equalTo: bubbleView.leadingAnchor, constant: 12).isActive = true
    messageLabel.trailingAnchor.constraint(equalTo: bubbleView.trailingAnchor, constant: -12).isActive = true
    messageLabel.topAnchor.constraint(equalTo: bubbleView.topAnchor, constant: 12).isActive = true
    
    hourLabel.trailingAnchor.constraint(equalTo: messageLabel.trailingAnchor).isActive = true
    hourLabel.topAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 4).isActive = true
    hourLabel.bottomAnchor.constraint(equalTo: bubbleView.bottomAnchor, constant: -12).isActive = true
    
    contentView.addSubview(bubbleView)
    
    bubbleView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4).isActive = true
    bubbleView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4).isActive = true
    bubbleView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor, constant: bubbleViewCenterXConstraintValue).isActive = true
    bubbleView.widthAnchor.constraint(lessThanOrEqualToConstant: availableMaxWidth).isActive = true
}

但是,每当调用 bubbleViewCenterXConstraintValue 时,bubbleView 的框架为零,因此它计算错误了我的逻辑。逻辑现在不包括左对齐或右对齐,它只是尝试右对齐。

当我查看那些打印结果时,我意识到了另一件奇怪的事情。 contentView 的宽度是 320,不等于 UIScreen.main.bounds.width(390).

(0.0, 0.0, 320.0, 44.0) (0.0, 0.0, 0.0, 0.0)
390.0 320.0 0.0 195.0
(0.0, 0.0, 390.0, 100.66666666666667) (0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 390.0, 100.66666412353516) (243.66666666666666, 4.0, 292.6666666666667, 92.66666666666667)
(0.0, 0.0, 390.0, 100.66666412353516) (243.66666666666666, 4.0, 292.6666666666667, 92.66666666666667)

我需要一种方法来使这些自动布局代码在设置 bubbleView 框架时更新。因为我知道如果它的宽度最初是 292,那么这段代码就可以工作。我尝试了当前无效的解决方案 setNeedsLayout() 并覆盖 layoutSubviews 但那也不起作用。

我知道我遗漏了一些东西,解决方案就在那里,但是我现在看不到,需要一些帮助。

预先感谢。

注:也在本站找了解决办法,没找到类似的。如果您认为这是重复的,请随时告诉我或采取行动。

我原以为更简单的方法是为气泡设置前导和尾随约束。这将使决定对齐屏幕的哪一侧变得容易。您还可以为宽度参数使用自动布局,使用基于父视图宽度的乘数使其适应任何尺寸的屏幕。

我不会将它用于您的代码,因为它太长了,但希望下面的示例函数能够展示我推荐的原则:

   func addBubble(alignLeft: Bool, offset: CGFloat) {
      let bubble = UIView()
      bubble.backgroundColor = .systemBlue
      let parentView = view.safeAreaLayoutGuide  //your parent view may be different
      parentView.addSubview(bubble)

      bubble.translatesAutoresizingMaskIntoConstraints = false
      
      //quick and dirty top and bottom constraints for the example
      bubble.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 10 + offset).isActive = true
      bubble.bottomAnchor.constraint(equalTo: parentView.topAnchor, constant: 40 + offset).isActive = true

      //set the width of the bubble proportional to the size of the parent view
      bubble.widthAnchor.constraint(equalTo: parentView.widthAnchor, multiplier: 2/3).isActive = true

      // implement the left or right alignment
      if alignLeft {
         bubble.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 4).isActive = true
      } else {
         bubble.trailingAnchor.constraint(equalTo: parentView.trailingAnchor, constant: -4).isActive = true
      }
   }

这样你所要做的就是将气泡的子视图锚定到气泡 top/bottom/leading/trailing 约束,它们也会随着气泡调整大小以适应所有屏幕尺寸。