【问题标题】:Different behaviour programmatically defined NSLayoutConstraints versus Storyboard constraints with 'greaterThanOrEqual'以编程方式定义的 NSLayoutConstraints 与带有“greaterThanOrEqual”的情节提要约束的不同行为
【发布时间】:2020-06-29 11:51:12
【问题描述】:

使用 NSLayoutConstraints 以编程方式与使用 Storyboard 或 Xib 配置约束相比,我得到了不同的(意外)行为。使用完全相同的约束。

我想要完成的是:一个 UILabel 在将其约束到超级视图的中心时调整其内在内容大小,并将前导和尾随约束关系设置为“greaterThanOrEqual”。

1. 故事板按预期工作。它将 UILabel 调整为其内在内容大小:

2. 程序化方法以全角显示UILabel,而不是Unable to simultaneously satisfy constraints.警告:

我创建了一个示例项目来说明问题:https://github.com/thomasneuteboom/temp-layout-constraints-issue

有人能指出我在这里遗漏的明显东西吗?故事板是否为 UILabel 提供了额外的(隐藏的)行为?

代码:

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let programmaticallyLabel = UILabel()
        programmaticallyLabel.text = "Programmatically example"
        programmaticallyLabel.textColor = .white
        programmaticallyLabel.backgroundColor = .blue
        self.view.addSubview(programmaticallyLabel)

//        programmaticallyLabel.sizeToFit()

        // Setup constraints.
        programmaticallyLabel.translatesAutoresizingMaskIntoConstraints = false
        let leadingConstraint = NSLayoutConstraint(item: programmaticallyLabel, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.greaterThanOrEqual, toItem: self.view.safeAreaLayoutGuide, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1, constant: 15)
        let trailingConstraint = NSLayoutConstraint(item: programmaticallyLabel, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.greaterThanOrEqual, toItem: self.view.safeAreaLayoutGuide, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: 15)
        let horizontalConstraint = NSLayoutConstraint(item: programmaticallyLabel, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view.safeAreaLayoutGuide, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
        let verticalConstraint = NSLayoutConstraint(item: programmaticallyLabel, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view.safeAreaLayoutGuide, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
        self.view.addConstraints([leadingConstraint, trailingConstraint, horizontalConstraint, verticalConstraint])
    }

【问题讨论】:

  • 你最好使用 NSLayoutConstraint.activate
  • 你真的应该使用布局锚。轻松多了

标签: ios swift xcode


【解决方案1】:

你需要它lessThanOrEqual 尾随

let trailingConstraint = NSLayoutConstraint(item: programmaticallyLabel, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.lessThanOrEqual, toItem: self.view.safeAreaLayoutGuide, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: -15)

如果您在 IB 中看到它,您会发现尾随第一个项目是超级视图的尾随,它是 greaterThanOrEqualTo 但在代码中您反转第一个项目,因此您必须反转关系,这里的顺序非常重要


顺便说一句

programmaticallyLabel.translatesAutoresizingMaskIntoConstraints = false 
NSLayoutConstraint.activate([
    programmaticallyLabel.leadingAnchor.constraint(greaterThanOrEqualTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 15),
    programmaticallyLabel.trailingAnchor.constraint(lessThanOrEqualTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: -15),
    programmaticallyLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor ),
    programmaticallyLabel.centerYAnchor.constraint(equalTo: self.view.centerYAnchor )
])

【讨论】:

    【解决方案2】:

    你的一个限制是错误的。常数应该是-15,关系应该是lessThanOrEqual:

        let trailingConstraint = NSLayoutConstraint(item: programmaticallyLabel, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.lessThanOrEqual, toItem: self.view.safeAreaLayoutGuide, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: -15)
    

    【讨论】:

      【解决方案3】:

      如果您不想给 lessThanOrEqual 约束而不是将 trailingConstraint 更改为此

      let trailingConstraint = NSLayoutConstraint(item: self.view.safeAreaLayoutGuide, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.greaterThanOrEqual, toItem: programmaticallyLabel, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: 15)
      

      【讨论】:

        【解决方案4】:

        来自您的 Main.storyboard:

        <label opaque="NO" 
               userInteractionEnabled="NO" 
               contentMode="left" 
               horizontalHuggingPriority="251" 
               verticalHuggingPriority="251" 
               text="Storyboard example" 
               textAlignment="natural" 
               lineBreakMode="tailTruncation" 
               baselineAdjustment="alignBaselines" 
               adjustsFontSizeToFit="NO"
               translatesAutoresizingMaskIntoConstraints="NO" 
               id="HPb-Ly-SNL">
        
        <constraints>
            <constraint firstItem="HPb-Ly-SNL" 
                        firstAttribute="centerY" 
                        secondItem="fsQ-UL-Fbk" 
                        secondAttribute="centerY" 
                        id="0Up-NL-qsu"/>
            <constraint firstItem="fsQ-UL-Fbk" 
                        firstAttribute="trailing" 
                        relation="greaterThanOrEqual" 
                        secondItem="HPb-Ly-SNL"
                        secondAttribute="trailing" 
                        constant="15" 
                        id="7xt-tj-mzn"/>
            <constraint firstItem="HPb-Ly-SNL" 
                        firstAttribute="leading" 
                        relation="greaterThanOrEqual" 
                        secondItem="fsQ-UL-Fbk" 
                        secondAttribute="leading" 
                        constant="15" 
                        id="Gyk-6R-ri3"/>
            <constraint firstItem="HPb-Ly-SNL" 
                        firstAttribute="centerX" 
                        secondItem="fsQ-UL-Fbk" 
                        secondAttribute="centerX" 
                        id="axh-b8-nGS"/>
        </constraints>
        <viewLayoutGuide key="safeArea" id="fsQ-UL-Fbk"/>
        

        你有(我只是添加了空格并删除了不必要的部分):

        let leadingConstraint = NSLayoutConstraint(item: programmaticallyLabel,
                                                   attribute: .leading,
                                                   relatedBy: .greaterThanOrEqual,
                                                   toItem: view.safeAreaLayoutGuide,
                                                   attribute: .leading,
                                                   multiplier: 1,
                                                   constant: 15)
        let trailingConstraint = NSLayoutConstraint(item: programmaticallyLabel,
                                                    attribute: .trailing,
                                                    relatedBy: .greaterThanOrEqual,
                                                    toItem: view.safeAreaLayoutGuide,
                                                    attribute: .trailing,
                                                    multiplier: 1,
                                                    constant: 15)
        let horizontalConstraint = NSLayoutConstraint(item: programmaticallyLabel,
                                                      attribute: .centerX,
                                                      relatedBy: .equal,
                                                      toItem: view.safeAreaLayoutGuide,
                                                      attribute: .centerX,
                                                      multiplier: 1,
                                                      constant: 0)
        let verticalConstraint = NSLayoutConstraint(item: programmaticallyLabel,
                                                    attribute: .centerY, relatedBy: .equal,
                                                    toItem: view.safeAreaLayoutGuide,
                                                    attribute: .centerY,
                                                    multiplier: 1,
                                                    constant: 0)
        

        几乎每个人都同意,但是,有区别。

        let trailingConstraint = NSLayoutConstraint(item: programmaticallyLabel,
                                                    attribute: .trailing,
                                                    relatedBy: .greaterThanOrEqual,
                                                    toItem: view.safeAreaLayoutGuide,
                                                    attribute: .trailing,
                                                    multiplier: 1,
                                                    constant: 15)
        

        <constraint firstItem="fsQ-UL-Fbk" 
                    firstAttribute="trailing" 
                    relation="greaterThanOrEqual" 
                    secondItem="HPb-Ly-SNL"
                    secondAttribute="trailing" 
                    constant="15" 
                    id="7xt-tj-mzn"/>
        

        顺序不同。
        您可以使用负值作为常量,如果在 Interface Builder 中您选择切换项目顺序,则该值变为负/正。
        这里,在 Storyboard 中,第一项 (id) 是 SafeArea,标签是第二项。在代码中,情况正好相反。
        因此,您可以改用常量 -15,或按代码更改这两项的顺序。此外,greaterThanOrEqual 可能需要更改(更改为 lessThanOrEqual,因为它是尾随)。

        在故事板中:

        目前您有:

        您可以更改:

        你将拥有:

        打开 Storyboard 的 XML:

        <constraint firstItem="HPb-Ly-SNL" 
                firstAttribute="trailing" 
                relation="lessThanOrEqual" 
                secondItem="fsQ-UL-Fbk" 
                secondAttribute="trailing" 
                constant="-15" 
                id="7xt-tj-mzn"/>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-27
          • 2015-06-12
          • 2015-02-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-28
          • 1970-01-01
          相关资源
          最近更新 更多