为什么我的 UISwitch 的尾部伸出了 UIStackView?

问题描述 投票:0回答:1

我不知道这是一个 Swift bug 还是我犯了一个错误,但有一个奇怪的行为。

我在水平 UIStackView 中有一个 UILabel 和一个 UISwitch,但 UISwitch 的尾部被切断,因为它伸出了 stackView(参见图片)。

App UI

UI debugger

有人有类似的问题还是只有我一个人有类似的问题? 如果这是 Swift 的错误,有解决方法吗?

这是我的代码:

private lazy var alreadyInPlaceStackView: UIStackView = {
    UIStackView(arrangedSubviews: [alreadyInPlaceLabel, alreadyInPlaceSwitch],
                axis: .horizontal,
                spacing: Constants.horizontalPadding,
                alignment: .fill,
                distribution: .fill)
}()

private lazy var alreadyInPlaceLabel: UILabel = {
    let label = UILabel()
    label.textColor = UIColor.conference.background.on_background
    label.numberOfLines = 1
    label.font = UIFont.label
    label.text = "report.intubation.already-in-place.title".localized()

    return label
}()

private lazy var alreadyInPlaceSwitch: UISwitch = {
    let view = UISwitch()
    view.onTintColor = UIColor.conference.highlight.primary
    view.addTarget(self,
                   action: #selector(switchValueDidChange(_:)),
                   for: .valueChanged)
    view.setContentCompressionResistancePriority(.required, for: .horizontal)

    return view
}()

限制:

alreadyInPlaceStackView.leadingAnchor.constraint(equalTo: switchStackViewContainerView.leadingAnchor),
alreadyInPlaceStackView.trailingAnchor.constraint(equalTo: switchStackViewContainerView.trailingAnchor),
alreadyInPlaceStackView.topAnchor.constraint(equalTo: videoLaryngoscopeStackView.bottomAnchor, constant: Constants.verticalPadding),
alreadyInPlaceStackView.bottomAnchor.constraint(equalTo: switchStackViewContainerView.bottomAnchor),

switchStackViewContainerView.leadingAnchor.constraint(equalTo: detailsContainer.leadingAnchor),
switchStackViewContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
switchStackViewContainerView.topAnchor.constraint(equalTo: difficultIntubationStackView.bottomAnchor, constant: Constants.verticalPadding),
switchStackViewContainerView.bottomAnchor.constraint(equalTo: detailsContainer.bottomAnchor),

谢谢!

swift uikit uistackview uiswitch
1个回答
0
投票

决定对此进行更多调查...我对“尾随”方面的看法是错误的。

让我们看一个简单的示例 - 我们将添加一个蓝色

UIView
和一个
UISwitch
,并将蓝色视图的宽度限制为开关的宽度:

class ViewController: UIViewController {
    
    let theSwitch: UISwitch = {
        let v = UISwitch()
        v.backgroundColor = .green
        return v
    }()
    
    let blueView: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground
        
        [blueView, theSwitch].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
        }
        
        view.addSubview(blueView)
        view.addSubview(theSwitch)
        
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // blueView width and height equal to theSwitch
            blueView.widthAnchor.constraint(equalTo: theSwitch.widthAnchor),
            blueView.heightAnchor.constraint(equalTo: theSwitch.heightAnchor),
            
            // blueView top and leading
            blueView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            blueView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            
            // theSwitch top to blueView bottom, leading to blueView leading
            theSwitch.topAnchor.constraint(equalTo: blueView.bottomAnchor, constant: 0.0),
            theSwitch.leadingAnchor.constraint(equalTo: blueView.leadingAnchor, constant: 0.0),
            
        ])
        
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("blueView  width:", blueView.frame.width)
        print("theSwitch width:", theSwitch.frame.width)
    }
    
}

这是我们得到的:

并且,如果我们点击,我们会在调试控制台中看到:

blueView  width: 49.0
theSwitch width: 51.0

开关比蓝色视图宽 2 点!!!


因此,让我们尝试在开关完全布局后设置蓝色视图的宽度约束。

我们注释掉宽度约束:

// don't set blueView width //blueView.widthAnchor.constraint(equalTo: theSwitch.widthAnchor), // blueView height equal to theSwitch blueView.heightAnchor.constraint(equalTo: theSwitch.heightAnchor),
点击后,我们将进行设置:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // now we set blueView width blueView.widthAnchor.constraint(equalTo: theSwitch.widthAnchor).isActive = true // print widths after layout pass DispatchQueue.main.async { print("blueView width:", self.blueView.frame.width) print("theSwitch width:", self.theSwitch.frame.width) } }
点击之前看起来像这样(因为 blueView 没有宽度):

点击后:

控制台输出又是:

blueView width: 49.0 theSwitch width: 51.0
平等显然并不总是平等!!!


让我们看一个常见的用例——我们将在视图(或者,如您的示例中,堆栈视图)中嵌入一个标签和一个开关,用于“选项”切换:

class ViewController: UIViewController { let theSwitch: UISwitch = { let v = UISwitch() v.backgroundColor = .green return v }() let blueView: UIView = { let v = UIView() v.backgroundColor = .systemBlue return v }() let theLabel: UILabel = { let v = UILabel() v.text = "Option 1:" return v }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground [blueView, theSwitch, theLabel].forEach { v in v.translatesAutoresizingMaskIntoConstraints = false } // let's embed theSwitch and theLabel in blueView blueView.addSubview(theLabel) blueView.addSubview(theSwitch) view.addSubview(blueView) let g = view.safeAreaLayoutGuide NSLayoutConstraint.activate([ // we're going to right-align the switch in the blue view blueView.widthAnchor.constraint(equalToConstant: 128.0), // blueView height equal to theSwitch + 16 (so we have 8-points top/bottom "padding" blueView.heightAnchor.constraint(equalTo: theSwitch.heightAnchor, constant: 16.0), // blueView top and leading blueView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0), blueView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0), // center theLabel vertically and left-align it theLabel.centerYAnchor.constraint(equalTo: blueView.centerYAnchor), theLabel.leadingAnchor.constraint(equalTo: blueView.leadingAnchor, constant: 0.0), // center theSwitch vertically theSwitch.centerYAnchor.constraint(equalTo: blueView.centerYAnchor), // right-align theSwitch theSwitch.trailingAnchor.constraint(equalTo: blueView.trailingAnchor, constant: 0.0), ]) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // clear the background colors blueView.backgroundColor = .clear theSwitch.backgroundColor = .clear // set clipsToBounds blueView.clipsToBounds = true } }
我们得到这个:

点击后我们将清除背景,并且我们将打开

clipsToBounds

 以获得蓝色视图:


这就是我所说的,显然,一个

bug

值得注意...如果我们评估开关的

intrinsicContentSize

print("theSwitch.intrinsicContentSize:", theSwitch.intrinsicContentSize) print("theSwitch.frame.size :", theSwitch.frame.size)
控制台显示:

theSwitch.intrinsicContentSize: (49.0, 31.0) theSwitch.frame.size : (51.0, 31.0)
    
© www.soinside.com 2019 - 2024. All rights reserved.