Where to update Autolayout constraints when size c

2019-01-26 10:29发布

问题:

I have several UIViews laid out along the bottom of a containing UIView. I want these views to always be equal width, and always stretch to collectively fill the width of the containing view (like the emoji keyboard buttons at the bottom). The way I'm approaching this is to set equal widths to one of the views, then just update the width constraint of that view to be superviewWidth / numberOfViews which will cause all of the other views to update to that same value.

I am wondering where the code to change the constraint constant needs to go. It needs to be set before the keyboard appears on screen for the first time and update when rotating the device.

My first attempt at a solution was to place it in updateViewConstraints and calculate the width via containerView.frame.size.width. But this method is called twice upon load, the first time it calculates the values correctly, but the second time for some reason the containerView's width is 0.0. Another issue is that when rotating, the containerView's width is not the value that it will be after rotation, it's the current value before rotation. But I don't want to wait until after the rotation completes to update the constraint, because the buttons will be the original size then change which will be jarring to the user.

My question is: where is the most appropriate place to put this code? Is there a better way to calculate what the width will be? I can guarantee it will always be the exact same width as the screen width. And I am using Size Classes in Xcode 6, so willRotateToInterfaceOrientation and similar methods are deprecated.

回答1:

There is no reason to update the width manually:

  1. Place all the views with equal width in your view with no spacing in between each other
  2. Add an equal width constraint to all of them
  3. Add constraints with 0 width for spacing between sides and each other
  4. Lower the priority of one or more of the equal width constraints just in case the width cannot be divided equally.

Then auto layout will handle everything for you.



回答2:

On all classes that implement the UITraitEnvironment protocol the method traitCollectionDidChange will be called when the trait collection changes, like on rotation. This is the appropiate place to manually update the constraints when using the new Size Classes. You can also animate the transition with the method willTransitionToTraitCollection

Basic example:

class ViewController: UIViewController {

  var constraints = [NSLayoutConstraint]()

  func updateConstraintsWithTraitCollection(traitCollection: UITraitCollection) {
    // Remove old constraints
    view.removeConstraints(constraints)

    // Create new constraints
  }

  override func willTransitionToTraitCollection(newCollection: UITraitCollection!,
    withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator!) {

      super.willTransitionToTraitCollection(newCollection, withTransitionCoordinator: coordinator)

      coordinator.animateAlongsideTransition({ (context: UIViewControllerTransitionCoordinatorContext!) in
        self.updateConstraintsWithTraitCollection(newCollection)
        self.view.setNeedsLayout()
      }, completion: nil)

  }

  override func traitCollectionDidChange(previousTraitCollection: UITraitCollection!) {
    updateConstraintsWithTraitCollection(traitCollection)
  }
}

Besides that I want to recommend Cartography, which is a nice library that helps to make auto layout more readable and enjoyable. https://github.com/robb/Cartography