Swift iOS应用程序中的布局问题(NSLayoutConstraint)

Swift iOS应用程序中的布局问题(NSLayoutConstraint),swift,autolayout,nslayoutconstraint,Swift,Autolayout,Nslayoutconstraint,在iOS应用程序中,我遇到了自动布局问题 以下两个屏幕截图显示了问题 右侧的开关(UISwitch对象)在应固定时水平移动。有人能看到发生了什么吗 左边的字符串确实在改变长度,但我认为(根据我设置约束的方式)字体应该调整大小或将字符串拆分为两行;但并不是开关被取代了 以下是相关的swift代码: import UIKit class My_ViewController: UIViewController { let xPanel = UILabel(), yPanel = UILa

在iOS应用程序中,我遇到了自动布局问题

以下两个屏幕截图显示了问题

右侧的开关(UISwitch对象)在应固定时水平移动。有人能看到发生了什么吗

左边的字符串确实在改变长度,但我认为(根据我设置约束的方式)字体应该调整大小或将字符串拆分为两行;但并不是开关被取代了

以下是相关的swift代码:

import UIKit

class My_ViewController: UIViewController {
    let xPanel = UILabel(), yPanel = UILabel(),
    khToggle = UISwitch(), khLabel = UILabel()
    ....

    override func viewDidLoad() {
        super.viewDidLoad()
        layOutUI()
    }


    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        .....
        toggleKeepHide(khToggle)
    }


    func layOutUI() {
        for component in [xPanel,yPanel,khLabel,khToggle] {
            component.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(component)
        }

        ...........

        khLabel.numberOfLines = 0
        khLabel.adjustsFontSizeToFitWidth = true
        khToggle.addTarget(self,
                                 action: #selector(toggleKeepHide(_:)),
                                 for: .valueChanged)

        view.addConstraints([
            .........
            NSLayoutConstraint(item: khToggle, attribute: .right, relatedBy: .equal,
                               toItem: view, attribute: .right, multiplier: 1.0,    constant: -30.0),
            NSLayoutConstraint(item: khToggle, attribute: .top, relatedBy: .equal,
                               toItem: yPanel, attribute: .bottom, multiplier: 1.0,
                               constant: 50.0),
            NSLayoutConstraint(item: khLabel, attribute: .right, relatedBy: .equal,
                               toItem: khToggle, attribute: .left, multiplier: 1.0,     constant: -23.0),
            NSLayoutConstraint(item: khLabel, attribute: .centerY, relatedBy: .equal,
                               toItem: khToggle, attribute: .centerY, multiplier: 1.0,  constant: 0.0),
            NSLayoutConstraint(item: khLabel, attribute: .left, relatedBy: .equal,
                               toItem: view, attribute: .left, multiplier: 1.0,     constant: 30.0)])
    }


    @objc func toggleKeepHide(_ sender: UISwitch) {
        if sender.isOn {khLabel.text = "Hide this object from the wyxoug list."}
        else {khLabel.text = "Keep this object in the wyxoug list."}
    }
}

标签和切换的水平约束相互竞争

(如果您进入Xcode的可视化调试器,您会发现有一个警告:
UISwitch
实例的宽度和水平位置不明确。)

解决方案

您为AutoLayout提供了绝对值,但它无法解决这些要求。要解决此问题,请通过将标签的抗压强度设置为较低的值,在要求中引入一些灵活性:

khLabel.setCompressionResistance(.defaultLow, for: .horizontal)

您没有提供足够的信息来重现问题。以下是我的视图控制器的
viewDidLoad
中代码的缩减(我删除了标签和开关之外的所有内容,修复了
左侧
右侧
(您永远不应该使用它们),并将两个视图之间的对齐改为
顶部
,而不是
中心
):

结果显示效果良好;不存在约束冲突或歧义,并且看起来正如人们所期望的:


有趣的答案。使用.left和.right有什么错;你不使用它们可能是对的,但最好有一些解释(甚至简短或只是一个链接)。到目前为止,我从未和他们有过任何争执。在你旁边使用。引导和。拖尾,我可能从未使用过。这里我可能也错了,虽然我已经成功地使用了NSLayoutConstraint很多次。使用前导和尾随是最好的方法。它允许UIKit从右向左翻转演示文稿,如希伯来语和阿拉伯语。马特,通过使用较小的设备宽度和增加标签文本中的字数,问题更容易重现。正如米歇尔指出的,UISwitch将被重新定位。在标签上使用较低的压缩阻力优先级将解决此问题。干杯。@Womble嗯,我不认为这能解释它,因为我确实增加了标签文本中的单词。很多如你所见。开关没有动。@matt,真奇怪。我能够使用他的约束条件,使用模拟器iphonexr,ios12复制它。如果使用“left”和“right”而不是“leading”和“training”,会发生什么?使用setContentCompressionResistancePriority可以完成这项工作。但我不太明白为什么UISwitch右侧的宽度(我不确定任何宽度)是固定的,因为它必须是固定的对象,我假设它的水平位置是完全确定的。您告诉AutoLayout将布局固定到精确的值,相对于对象和superview。但它无法根据属性的固有宽度解析这些精确值。通过为其中一个项目提供较低的压缩阻力,您告诉AutoLayout可以减小其中一个项目的宽度,从而允许它解析布局。好的,我明白了。在我看来,自动布局可以自由压缩或折叠标签。这是我的错误。虽然有时候似乎是这样的。别担心,不只是你。这是一组困难的API,尤其是多行标签。希望几年后的某一天,SwiftUI会让这些问题成为过去。
    khToggle = UISwitch()
    khToggle.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(khToggle)

    khLabel = UILabel()
    khLabel.text = String(repeating: "word ", count: 40)
    khLabel.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(khLabel)


    // Do any additional setup after loading the view.
    khLabel.numberOfLines = 0

    view.addConstraints([
        NSLayoutConstraint(item: khToggle!, attribute: .trailing, relatedBy: .equal,
                               toItem: view, attribute: .trailing, multiplier: 1.0,    constant: -30.0),
        NSLayoutConstraint(item: khToggle!, attribute: .top, relatedBy: .equal,
                           toItem: view, attribute: .top, multiplier: 1.0,
                           constant: 50.0),
        NSLayoutConstraint(item: khLabel!, attribute: .trailing, relatedBy: .equal,
                           toItem: khToggle, attribute: .leading, multiplier: 1.0,     constant: -23.0),
        NSLayoutConstraint(item: khLabel!, attribute: .top, relatedBy: .equal,
                           toItem: khToggle, attribute: .top, multiplier: 1.0,  constant: 0.0),
        NSLayoutConstraint(item: khLabel!, attribute: .leading, relatedBy: .equal,
                           toItem: view, attribute: .leading, multiplier: 1.0,     constant: 30.0)])