I have a four buttons layout. In portrait they should be shown one above the other. In landscape they should be in two columns each with two buttons.
I implement the buttons in code - really simple stuff:
UIButton *btn1 = [[UIButton alloc] init]; [self.view addSubview: btn1]; UIButton *btn2 = [[UIButton alloc] init]; [self.view addSubview: btn2]; UIButton *btn3 = [[UIButton alloc] init]; [self.view addSubview: btn3]; UIButton *btn4 = [[UIButton alloc] init]; [self.view addSubview: btn4]; NSDictionary *views = NSDictionaryOfVariableBindings(btn1, btn2, btn3, btn4); [btn1 setTranslatesAutoresizingMaskIntoConstraints:NO]; [btn2 setTranslatesAutoresizingMaskIntoConstraints:NO]; [btn3 setTranslatesAutoresizingMaskIntoConstraints:NO]; [btn4 setTranslatesAutoresizingMaskIntoConstraints:NO]; // portrait constraints [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn1]-(50)-|" options:0 metrics:nil views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn2]-(50)-|" options:0 metrics:nil views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn3]-(50)-|" options:0 metrics:nil views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn4]-(50)-|" options:0 metrics:nil views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[btn1]-[btn2]-[btn3]-[btn4]-(50)-|" options:0 metrics:nil views:views]];
This is obviously the setup for portrait layout. I would used to have determined the device and its orientation to make specific case for iPad and iPhone in there respective orientations. But now we are supposed to use size classes. How can I determine if the size class is "compact"... and thus set the appropriate constraints?
Four of these are the Final size classes: Compact-Compact, Compact-Regular, Regular-Compact, and Regular-Regular.
In easy way we can say Autolayout is used for displaying same layout comatible on different different iPhone/iPad screen sizes (ex. Keep button in center for all screen sizes) while through Autoresizing classes we can set a different layout for a particular screen size.
Size classes help you change the layout of views to adapt to various screen sizes, ranging from a tiny iPhone SE to a massive 12.9” iPad Pro. There are 3 different cases for a size class: regular , compact , and unspecified .
In the meantime I have found a good solution. Since this question has so many upvotes, I thought I would quickly describe it. I was inspired to this solution by a WWDC session.
I have moved on to Swift so please excuse that the code will be in swift - the concept is however the same for Obj-C.
You start out by declaring three constraint arrays:
// Constraints private var compactConstraints: [NSLayoutConstraint] = [] private var regularConstraints: [NSLayoutConstraint] = [] private var sharedConstraints: [NSLayoutConstraint] = []
And then you fill the constraints accordingly. You can i.e. do this in a separate function that you call from viewDidLoad
or you do it in viewDidLoad
directly.
sharedConstraints.append(contentsOf: [ btnStackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), ... ]) compactConstraints.append(contentsOf: [ btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.7), ... ]) regularConstraints.append(contentsOf: [ btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.4), ... ])
The important part is switching between the size classes and activating/deactivating the appropriate constraints.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if (!sharedConstraints[0].isActive) { // activating shared constraints NSLayoutConstraint.activate(sharedConstraints) } if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular { if regularConstraints.count > 0 && regularConstraints[0].isActive { NSLayoutConstraint.deactivate(regularConstraints) } // activating compact constraints NSLayoutConstraint.activate(compactConstraints) } else { if compactConstraints.count > 0 && compactConstraints[0].isActive { NSLayoutConstraint.deactivate(compactConstraints) } // activating regular constraints NSLayoutConstraint.activate(regularConstraints) } }
I know that the constraints don't fit to the ones in the question. But the constraints themselves are irrelevant. The main thing is how one switches between two sets of constraints based on the size class.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With