Swift 4:设备旋转后 UI 无法更新

Posted

技术标签:

【中文标题】Swift 4:设备旋转后 UI 无法更新【英文标题】:Swift 4: UI fails to update after device rotation 【发布时间】:2019-07-07 07:51:01 【问题描述】:

我想将我的bearImageView 的宽度和高度从纵向 -> 横向更改为 100,在相反方向更改为 200。

setupLayout 内部,我正在调用停用然后激活widthAnchorheightAnchor 上的约束。所以我期待它改变宽度和高度。

问题:变为 100,但不会变回 200。 为什么会这样?

这是代码。

class ViewController: UIViewController 

    // closure objects
    let bearImageView: UIImageView = 
        let imageView = UIImageView(image: #imageLiteral(resourceName: "bear_first")) // type `image literal` and double click
        imageView.translatesAutoresizingMaskIntoConstraints = false // enable autolayout
        return imageView
    ()

    override func viewDidLoad() 
        super.viewDidLoad()            
        view.addSubview(bearImageView) // display image        
        setupLayout(imageView: bearImageView) // apply constraints
    

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 
        super.viewWillTransition(to: size, with: coordinator)
        if UIDevice.current.orientation.isLandscape 
            print("landscape")
            setupLayout(imageView: bearImageView) // apply constraints                
         else 
            print("portrait")
            setupLayout(imageView: bearImageView) // apply constraints                
        
    

    private func setupLayout(imageView: UIImageView)

        if UIDevice.current.orientation.isLandscape == true 
            imageView.widthAnchor.constraint(equalToConstant: 200).isActive = false
            imageView.heightAnchor.constraint(equalToConstant: 200).isActive = false
            imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
            imageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
            imageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
            print("changed to landscape")

         else 
            imageView.widthAnchor.constraint(equalToConstant: 100).isActive = false
            imageView.heightAnchor.constraint(equalToConstant: 100).isActive = false
            imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
            imageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
            imageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
            print("changed to portrait")
        

    

这是错误。

[LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x6000031923a0 UIImageView:0x7fbf72508060.width == 200   (active)>",
    "<NSLayoutConstraint:0x6000031e4730 UIImageView:0x7fbf72508060.width == 100   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6000031923a0 UIImageView:0x7fbf72508060.width == 200   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.

【问题讨论】:

【参考方案1】:

请注意,constraint 方法会为您的图像视图创建 new

当您第一次在viewDidLoad 中调用setupLayout 时,会将200 的宽度和高度约束添加到图像视图中。然后旋转设备以更改为横向。 setupLayout 再次被调用。这次它添加了 100 的宽度和高度约束,但它不会停用您之前添加的常量 200 的约束。这样做:

imageView.widthAnchor.constraint(equalToConstant: 200).isActive = false

创建一个新的非活动约束,停用一个旧约束。

你应该做的是将宽度和高度约束存储为ViewController的属性:

var widthConstraint: NSLayoutConstraint!
var heightConstraint: NSLayoutConstraint!

setupLayout 中,分配给这些属性:

private func setupLayout(imageView: UIImageView)
    widthConstraint = imageView.widthAnchor.constraint(equalToConstant: 200)
    heightConstraint = imageView.heightAnchor.constraint(equalToConstant: 200)
    widthConstraint.isActive = true
    heightConstraint.isActive = true
    imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true


而且您应该只调用一次setupLayout

然后您创建另一个名为 updateConstraints 的方法来更新 widthConstraintheightConstraint 的常量:

private func updateConstraints() 
    if UIDevice.current.orientation.isLandscape 
        heightConstraint.constant = 100
        widthConstraint.constant = 100
     else 
        heightConstraint.constant = 200
        widthConstraint.constant = 200
    

viewWillTransitionToSize 代替setupLayout 调用它。

【讨论】:

谢谢!我想应该是这样的!顺便说一句,您的 setupLayout() 中缺少这两行。 `widthConstraintImage.isActive = true heightConstraintImage.isActive = true`

以上是关于Swift 4:设备旋转后 UI 无法更新的主要内容,如果未能解决你的问题,请参考以下文章

UI 测试失败:无法更新到请求的方向

无法在 C# 中更新 UI 组件

无法在 Swift 4 上的 XCUITest 中设置设备方向

仪器无法在 Xcode 4.4 的真实 iOS 设备中运行 GUI 测试脚本

无法使用锚定查询获取重量样本

Swift:如何在设备旋转后刷新UICollectionView布局