自动旋转时自动布局约束更新

Posted

技术标签:

【中文标题】自动旋转时自动布局约束更新【英文标题】:Autolayout constraints update on autorotation 【发布时间】:2019-10-10 14:42:53 【问题描述】:

我对纵向和横向模式有不同的自动布局约束。我在旋转时激活和停用它们,但对于已停用的约束,仍然会出现无法满足的约束错误。这是我的工作:

  //Initialization


    slider.translatesAutoresizingMaskIntoConstraints = false

    view.addSubview(slider)


    let landscapeConstraintTrailing = slider.trailingAnchor.constraint(equalTo: topPanel.trailingAnchor, constant: 0)
    let landscapeConstraintTop = slider.topAnchor.constraint(equalTo: topPanel.bottomAnchor, constant: 5)

    let landscapeConstraintBottom = slider.bottomAnchor.constraint(equalTo: bottomPanel.topAnchor, constant: -5)
    let landscapeConstraintWidth = slider.widthAnchor.constraint(equalToConstant: 140)

     self.sliderLandscapeConstraints = [landscapeConstraintTrailing,
                                          landscapeConstraintTop,
                                          landscapeConstraintBottom,
                                          landscapeConstraintWidth]

     for constraint in self.sliderLandscapeConstraints! 
           constraint.isActive = false
       

   let portraitConstraintTrailing = slider.trailingAnchor.constraint(equalTo: bottomPanel.trailingAnchor, constant: -10)
   let portraitConstraintBottom = slider.bottomAnchor.constraint(equalTo: bottomPanel.topAnchor, constant: -10)
   let portraitConstraintLeading = slider.leadingAnchor.constraint(equalTo: bottomPanel.leadingAnchor, constant: 10)
   let portraitconstraintHeight = slider.heightAnchor.constraint(equalToConstant: 140)

     self.sliderPortraitConstraints = [portraitConstraintTrailing,
                                         portraitConstraintBottom,
                                         portraitConstraintLeading,
                                         portraitconstraintHeight
                                        ]



     for constraint in self.sliderPortraitConstraints! 
          constraint.isActive = false
     

现在在自动旋转,我这样做:

   override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 

        let orientation = UIApplication.shared.statusBarOrientation

          super.viewWillTransition(to: size, with: coordinator)



         coordinator.animate(alongsideTransition:  [unowned self] (_) in

        let orient = UIApplication.shared.statusBarOrientation

        layoutSlider(orient)

    , completion:  [unowned self] (UIViewControllerTransitionCoordinatorContext) -> Void in

        let orient = UIApplication.shared.statusBarOrientation
        layoutSlider(orient)

    )


private func layoutSlider(_ orient:UIInterfaceOrient) 

    if orient.isLandscape 
         for constraint in self.sliderLandscapeConstraints! 
                constraint.isActive = true
          

         for constraint in self.sliderPortraitConstraints! 
               constraint.isActive = false
         
     else 

         for constraint in self.sliderLandscapeConstraints! 
                constraint.isActive = false
          

         for constraint in self.sliderPortraitConstraints! 
               constraint.isActive = true
         


       

  

这是我在自动旋转时遇到的错误:

      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.

2019-10-10 20:12:22.371021+0530 MyApp[1844:173193] [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:0x2810051d0 UIView:0x103a1d130.leading == UILayoutGuide:0x280a28b60'UIViewSafeAreaLayoutGuide'.leading + 5   (active)>",
  "<NSLayoutConstraint:0x2810014f0 UIView:0x103a1d130.trailing == UILayoutGuide:0x280a28b60'UIViewSafeAreaLayoutGuide'.trailing + 5   (active)>",
  "<NSLayoutConstraint:0x28101e490 MyApp.slider:0x103b2deb0.trailing == UIView:0x103a1d130.trailing - 10   (active)>",
  "<NSLayoutConstraint:0x28101e3a0 MyApp.slider:0x103b2deb0.leading == UIView:0x103a1d130.leading + 10   (active)>",
  "<NSLayoutConstraint:0x28101e350 MyApp.slider:0x103b2deb0.width == 140   (active)>",
  "<NSLayoutConstraint:0x281060690 'UIView-Encapsulated-Layout-Width' UIView:0x103b23410.width == 812   (active)>",
  "<NSLayoutConstraint:0x281001900 'UIViewSafeAreaLayoutGuide-left' H:|-(44)-[UILayoutGuide:0x280a28b60'UIViewSafeAreaLayoutGuide'](LTR)   (active, names: '|':UIView:0x103b23410 )>",
    "<NSLayoutConstraint:0x2810019a0 'UIViewSafeAreaLayoutGuide-right' H:[UILayoutGuide:0x280a28b60'UIViewSafeAreaLayoutGuide']-(44)-|(LTR)   (active, names: '|':UIView:0x103b23410 )>"

)

Will attempt to recover by breaking constraint 
   <NSLayoutConstraint:0x28101e350 MyApp.slider:0x103b2deb0.width == 140   (active)>

【问题讨论】:

【参考方案1】:

顺序很重要,您应该先停用然后再激活,以免造成冲突

private func layoutSlider(_ orient:UIInterfaceOrient) 

    if orient.isLandscape 
         // false should be first
         for constraint in self.sliderPortraitConstraints! 
               constraint.isActive = false
         

         for constraint in self.sliderLandscapeConstraints! 
                constraint.isActive = true
          

     else 
          // false should be first
         for constraint in self.sliderLandscapeConstraints! 
                constraint.isActive = false
          

         for constraint in self.sliderPortraitConstraints! 
               constraint.isActive = true
          

        

【讨论】:

糟糕,就是这样。

以上是关于自动旋转时自动布局约束更新的主要内容,如果未能解决你的问题,请参考以下文章

设备旋转时是不是有动画自动布局(约束)?

ScrollView 自动布局约束打破设备旋转

任何自动布局大师能够启发我约束和旋转?

使用自动布局约束旋转后对齐 UILabel 文本

自动布局、约束和旋转

自动布局 [Snapkit] 更改旋转约束