简体   繁体   中英

Programmatically create auto layout constraints with different constants for different size classes

If you use a Storyboard, you can add auto layout constraints to a view using Interface Builder, and you can very easily add different constant values for each size class you want. When you run the app and switch between size classes, the UI will automatically update and reposition to respect the correct constant value for the new size class.

My question is how can you obtain that same behavior programmatically?

When you create an NSLayoutConstraint you can't set different values for different size classes. I'm therefore thinking it would be a much more manual process. You'd have to create the constraints with the correct value for the current size class in viewDidLoad for example, then you'd have to use willTransitionToTraitCollection or maybe updateConstraints and detect the new size class, then change the constant s for all of the constraints that's appropriate for the new size class, then call layoutIfNeeded on the views that need to be repositioned. That would be a lot of code, made worse the more size classes you optimize for. Is there not an easier and/or more efficient way to obtain that behavior programmatically?

Note that this question isn't limited to auto layout constraints but rather any object that can have its properties' values change based on size class. For example, setting a UILabel 's font for different size classes.

Swift

You need to create different sets of NSLayoutConstraint .

Edit as per discussion below.

  • @Joey : You have to handle size classes decision in both viewDidLoad (or similar) and viewWillTransitionToSize .

  • Size class detection should be done inside the animateAlongsideTransition block, not before.

Refactored code:

override func viewDidLoad() {
    super.viewDidLoad()
    let narrow = self.view.traitCollection.horizontalSizeClass 
                 == UIUserInterfaceSizeClass.Compact
    self.useNarrowConstraints(narrow)
}


override func viewWillTransitionToSize(size: CGSize,
                                       withTransitionCoordinator
                                       coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition({
        (UIViewControllerTransitionCoordinatorContext) -> Void in
            let narrow = self.view.traitCollection.horizontalSizeClass 
                         == UIUserInterfaceSizeClass.Compact
            self.useNarrowConstraints(narrow)
        })
        { (UIViewControllerTransitionCoordinatorContext) -> Void in 
        }
}

Using Activation:

func useNarrowConstraints(narrow: Bool) {
    if narrow {
        NSLayoutConstraint.deactivateConstraints([self.fullWidthConstraint])
        NSLayoutConstraint.activateConstraints([self.halfWidthConstraint])
    } else {
        NSLayoutConstraint.deactivateConstraints([self.halfWidthConstraint])
        NSLayoutConstraint.activateConstraints([self.fullWidthConstraint])
    }
}

Further details here .

Using Substitution:

func useNarrowConstraints(narrow: Bool) {
    view.removeConstraint(constraint)

    if narrow {
        constraint = NSLayoutConstraint.constraintsWithVisualFormat("format", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
    } else {
        constraint = NSLayoutConstraint.constraintsWithVisualFormat("otherFormat", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
    }
    view.addConstraint(constraint)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM