【问题标题】:UITableViewCell auto-layout issue with centerXAnchor set使用 centerXAnchor 设置的 UITableViewCell 自动布局问题
【发布时间】:2021-03-30 21:19:10
【问题描述】:

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

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

提前表示感谢。

注意:还找了解决方案,在网站上找不到类似的东西。如果您认为这是重复的,请随时告诉我或采取行动。

【问题讨论】:

  • 如果我没看错的话,您想通过将中心点向右移动一半,使气泡与屏幕的宽度不同,从而将气泡放在屏幕上,与右边缘对齐。虽然逻辑在理论上是有道理的,但这似乎是一种奇怪的方式。另外,正如您所意识到的,边界在自动布局完成之前是有效的,因此它在实践中不起作用。是否有理由决定使用视图边界而不是全部在自动布局中?以及您尝试偏移中心而不是使用尾随约束的任何原因?
  • 是的,你是对的。我正在使用bounda,因为气泡的宽度是有限的,但可以改变。作为第二个问题的答案,我只是认为这样会更容易,而不是有两个约束 - 前导和尾随 - 并分别激活/停用它们
  • 我错过了上面的一个重要词:在自动布局完成之前,边界无效有效(如果所有布局都使用自动布局,那么也不是)

标签: swift uitableview autolayout


【解决方案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
      }
   }

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

【讨论】:

  • 我用你的建议解决了这个问题。我在UITableViewCell 课堂上处理过。
  • 虽然我开始认为UICollectionView 可能会更方便的方式来完成这样的任务
  • 不知道应用程序设计这有点难说,但我可能只是使用滚动视图并继续附加气泡作为子视图。不过,这个概念在任何地方都是一样的。
猜你喜欢
  • 2017-02-13
  • 2013-10-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多