iOS Auto Layout 在空间不够的时候保持最小的间隙,在空间足够的时候尽可能的占用空间

标签 ios swift autolayout masonry snapkit

enter image description here
这是布局。顶部的标签文本可能会变得很长,我希望在底部选择的标签此刻有足够的空间时距离底部按钮至少 40 pt,而当空间不足时至少 10 pt。尝试优先排序,但似乎不起作用,请帮助我。这是我的代码的一部分。

buttonView.snp.updateConstraints { (make) in
  make.leading.bottom.trailing.equalToSuperview()
  make.height.equalTo(buttonView.intrinsicContentSize.height)
}

contentLabel.snp.updateConstraints { (make) in
  make.top.greaterThanOrEqualTo(headerImageView.snp.bottom).offset(10.dp)
  make.leading.equalTo(50.dph)
  make.trailing.equalTo(-50.dph)
}

codeTextField.snp.updateConstraints { (make) in
  make.top.equalTo(contentLabel.snp.bottom).offset(10.dp)
  make.leading.equalTo(46.5.dp)
  make.trailing.equalTo(-46.5.dp)
  make.height.equalTo(50.dp)
}

tipsLabel.snp.updateConstraints { (make) in
  make.top.equalTo(codeTextField.snp.bottom).offset(10.dp)
  make.width.centerX.equalTo(codeTextField)
  make.bottom.equalTo(buttonView.snp.top).offset(-10.dp)
  make.bottom.greaterThanOrEqualTo(buttonView.snp.top).offset(-40.dp)
}
Click here下载演示项目。

最佳答案

几件事...
首先,您要在“提示”标签上设置抗压性,这样它就不会被挤出来。
其次,当你给一个对象约束时,例如:

bottom of viewA greaterThanOrEqual to -40 from top of viewB
bottom of viewA lessThanOrEqual to -10 from top of viewB
你还没有给出完整的布局。 任何 -40 和 -10 之间的值是有效的,因此自动布局无法理解您真正想要的内容。
为了解决这个问题,根据你的描述,如果可能的话,你想要 40 分,至少 10 分。所以你想要两个约束:
  • viewA 底部 at least -10 从 View B 的顶部
  • viewA 底部 equalTo -40 从 View B 的顶部 - 除非空间不够 - 所以给它一个Priority小于 required

  • 试试这个代码 - 我添加了 // MARK: DonMag ...我进行更改的评论:
    class MyView: UIView {
    
      override class var requiresConstraintBasedLayout: Bool { return true }
    
        // MARK: DonMag - a few varied length contentLabel strings
        private var idx: Int = 0
        private let examples: [String] = [
            "Check your email.",
            "Please check your email to activate your account.\n\nEnter the activation code:",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
        ]
    
      private let headerView = UIButton().then {
        $0.backgroundColor = .purple
        $0.setTitle("Tap me!", for: .normal)
      }
    
      private let contentLabel = UILabel().then {
        $0.font = .systemFont(ofSize: 21)
        $0.numberOfLines = 0
        $0.setContentHuggingPriority(.required, for: .vertical)
        
        // MARK: DonMag - so we can see its frame
        $0.textAlignment = .center
        $0.backgroundColor = .cyan
    
      }
    
      private let codeTextField = UITextField().then {
        $0.placeholder = "Enter code"
        $0.backgroundColor = UIColor.white.withAlphaComponent(0.2)
        $0.layer.cornerRadius = 8
        $0.layer.borderWidth = 1
        $0.layer.borderColor = UIColor.lightGray.cgColor
        $0.textAlignment = .center
        $0.font = .systemFont(ofSize: 21)
        $0.keyboardType = .numberPad
      }
    
      private let tipsLabel = UILabel().then {
        $0.font = .systemFont(ofSize: 12)
        $0.adjustsFontSizeToFitWidth = true
        $0.minimumScaleFactor = 0.2
        $0.textAlignment = .center
        $0.text = "If you have not received the code, tap 'resend'."
        $0.setContentHuggingPriority(.required, for: .vertical)
        
        // MARK: DonMag - prevent label from being compressed vertically
        $0.setContentCompressionResistancePriority(.required, for: .vertical)
        // MARK: DonMag - so we can see its frame
        $0.backgroundColor = .yellow
    
      }
    
      private let bottomView = UIView().then {
        $0.backgroundColor = .red
      }
    
      override init(frame: CGRect) {
        super.init(frame: frame)
    
        backgroundColor = .white
    
        addSubview(headerView)
        addSubview(contentLabel)
        addSubview(codeTextField)
        addSubview(tipsLabel)
        addSubview(bottomView)
    
        headerView.addTarget(self, action: #selector(headerViewDidTapped), for: .touchUpInside)
        headerViewDidTapped()
      }
    
      override func updateConstraints() {
        headerView.snp.updateConstraints { (make) in
          make.leading.trailing.top.equalToSuperview()
          make.height.equalToSuperview().multipliedBy(0.454)
        }
    
        bottomView.snp.updateConstraints { (make) in
          make.leading.bottom.trailing.equalToSuperview()
          make.height.equalTo(121)
        }
    
        contentLabel.snp.updateConstraints { (make) in
          make.top.greaterThanOrEqualTo(headerView.snp.bottom).offset(10)
          make.leading.equalTo(50)
          make.trailing.equalTo(-50)
        }
    
        codeTextField.snp.updateConstraints { (make) in
          make.top.equalTo(contentLabel.snp.bottom).offset(10)
          make.leading.equalTo(46.5)
          make.trailing.equalTo(-46.5)
          make.height.equalTo(50)
        }
    
        tipsLabel.snp.updateConstraints { (make) in
          make.top.equalTo(codeTextField.snp.bottom).offset(10)
          make.width.centerX.equalTo(codeTextField)
          make.bottom.greaterThanOrEqualTo(bottomView.snp.top).offset(-40)
            
          // MARK: DonMag - tipsLabel bottom should be equalTo -40 with medium priority (so it can be overridden by auto-layout when needed)
          //make.bottom.greaterThanOrEqualTo(bottomView.snp.top).offset(-40)
          make.bottom.equalTo(bottomView.snp.top).offset(-40).priority(.medium)
            
          make.bottom.lessThanOrEqualTo(bottomView.snp.top).offset(-10)
        }
    
        super.updateConstraints()
      }
    
      required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
    
      @objc
      private func headerViewDidTapped() {
    
        // MARK: DonMag - get example string for contentLabel
        let text = examples[idx % examples.count]
        idx += 1
    
        contentLabel.text = text
        setNeedsUpdateConstraints()
    
        UIView.animate(withDuration: 0.1) {
          self.layoutIfNeeded()
        }
      }
    
    }
    

    关于iOS Auto Layout 在空间不够的时候保持最小的间隙,在空间足够的时候尽可能的占用空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63769505/

    相关文章:

    ios - FacebookSDK 无法登录,授权后出现空白屏幕。

    ios - UI 模板 View - iOs 应用程序所有场景中的通用 UI 元素?

    ios - 使用 UITableViewCell 的自动布局约束以显示两个 View

    ios - UITableViewCell 调整大小不流畅

    ios - 从另一个类捕获一个 View Controller 的图像

    ios - 如何在 Action 边界停止 SKAction.repeatActionForever Action ?

    ios - 尽管受到限制,为什么导航栏顶部和安全区域顶部之间仍然存在空间?

    iOS 8 自定义键盘自动布局键

    swift - 如何快速检查对象是否属于动态类类型?

    swift - 在每次请求之前重新加载凭据是一种好习惯吗?