设置 centerXAnchor 的 UITableViewCell 自动布局问题

时间:2021-03-30 21:19:10

标签: swift uitableview autolayout

我正在尝试构建消息传递界面并遇到了这个问题。由于这是消息传递应用程序,因此消息气泡会对齐前导或尾随。我想做这种事情,创建一个名为 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,但这也不起作用。

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

提前感谢。

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

1 个答案:

答案 0 :(得分:1)

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

我不会将它添加到您的代码中,因为它会太长,但希望下面的示例函数将展示我推荐的原则:

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

这样,您所要做的就是将气泡的子视图锚定到气泡的顶部/底部/前导/尾随约束,并且它们还将随着气泡调整大小以适应所有屏幕尺寸。