Different size classes for iPad portrait and landscape modes with containerviews
Asked Answered
T

3

4

I've found this question and I've tried to implement the solution that has been given. However I run into a problem.

My initial view controller has two container views who both have their own view controller. I've created a root view controller that is assigned to the initial view controller. The code in this class looks like this.

class RootViewController: UIViewController {

var willTransitionToPortrait: Bool!
var traitCollection_CompactRegular: UITraitCollection!
var traitCollection_AnyAny: UITraitCollection!

override func viewDidLoad() {
    super.viewDidLoad()
    setupReferenceSizeClasses()
    // Do any additional setup after loading the view.
}

override func viewWillAppear(animated: Bool) {
    willTransitionToPortrait = self.view.frame.size.height > self.view.frame.size.width
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    willTransitionToPortrait = size.height > size.width
}

func setupReferenceSizeClasses(){
    let traitCollection_hCompact = UITraitCollection(horizontalSizeClass: .Compact)
    let traitCollection_vRegular = UITraitCollection(verticalSizeClass: .Regular)
    traitCollection_CompactRegular = UITraitCollection(traitsFromCollections: [traitCollection_hCompact, traitCollection_vRegular])
    
    let traitCollection_hAny = UITraitCollection(horizontalSizeClass: .Unspecified)
    let traitCollection_vAny = UITraitCollection(verticalSizeClass: .Unspecified)
    traitCollection_AnyAny = UITraitCollection(traitsFromCollections: [traitCollection_hAny, traitCollection_vAny])
}

override func overrideTraitCollectionForChildViewController(childViewController: UIViewController) -> UITraitCollection? {
    let traitCollectionForOverride = ((willTransitionToPortrait) != nil) ? traitCollection_CompactRegular : traitCollection_AnyAny
    
    return traitCollectionForOverride;
}

However when I run it the size class won't respons like it should. One of the container view controllers will start acting weird in both landscape and portrait mode like can be seen below.

landscape mode portrait mode

When I don't assign the rootviewcontroller it will look like this landscape mode portrait mode

While it should look like this in portrait mode portrait mode how it should look

Does anyone know what might be going wrong here? Why it doesn't change the size class like desired.

EDIT Like @Muhammad Yawar Ali asked here are screenshots from the position of all the size classes I've set. I have no warnings or errors on any constraints so these screenshots contain the updated views.

enter image description here enter image description here

I hope this shows everything that is needed.

EDIT: for some reason I'm unable to put in all the screenshots

Tessie answered 10/3, 2016 at 11:37 Comment(0)
H
2

On the viewWillTransitionToSize you need to call also super, to pass the event to the next responder (your rootviewcontroller)...

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    willTransitionToPortrait = size.height > size.width
}
Hundred answered 21/3, 2016 at 9:33 Comment(1)
I applied the super but it didn't change anything unfortunatelyTessie
T
0

Realize this is over two years old but...

I just ran across what I think is a similar issue. What you may be forgetting is that 'overrideTraitCollectionForChildViewController' only overrides the views children, so this method won't do anything with the containers since they are located at the root.

I solved this putting my two containers in a UIStackView in Interface Builder and made a property of this stack in code and then updated the axis depending on the orientation. For example, in Objective-C:

@property (weak, nonatomic) IBOutlet UIStackView *rootStack;

// ...

- (UITraitCollection *)overrideTraitCollectionForChildViewController:(UIViewController *)childViewController
{
    if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
        return [super overrideTraitCollectionForChildViewController:childViewController];
    }

    if (CGRectGetWidth(self.view.bounds) < CGRectGetHeight(self.view.bounds)) {
        self.rootStack.axis = UILayoutConstraintAxisVertical;
        return [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];
    }
    else {
        self.rootStack.axis = UILayoutConstraintAxisHorizontal;
        return [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];
}

If you have any constraints that are different between portrait and landscape you will need to adjust those in code as well.

I suppose you could also solve this by embedding the view controller with the containers in another view controller.

Torbert answered 21/4, 2018 at 16:5 Comment(0)
M
-1

I have cloned your code from repository : https://github.com/MaikoHermans/sizeClasses.git And editted code put the below code in you controller it will work fine & will not effect your design in iPads. import UIKit

class RootViewController: UIViewController {

   override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view.
   }

   override func overrideTraitCollectionForChildViewController(childViewController: UIViewController) -> UITraitCollection? {
      if view.bounds.width < view.bounds.height {
         return UITraitCollection(horizontalSizeClass: .Unspecified)
      } else {
         return UITraitCollection(horizontalSizeClass: .Regular)
      }
   }
}

You can try with this code but There is an issue i believe its not updating traits properly for ipads and view layout remains same but looks good. I have tried multiple ways but not succeeded yet will update my answer.

Mohamedmohammad answered 21/3, 2016 at 10:29 Comment(6)
I have applied the constraints in all the needed directions. They do work like they should when I run it on any iPhone device. It just won't work on any iPad devicesTessie
@Tessie Can you confirm in which dimensions you are applying constraints ? For constraints to work on all device you must apply them in wAny*hAny base values dimension. In order to make design work on multiple devices you have to add constraints in multiple dimensions.Mohamedmohammad
Look at the edit I just made. I've changed all the size classes I tried to put all the screenshots in however for some reason I'm unable to post more screenshots then it currently hasTessie
@Tessie select wRegularhRegular dimension and design the ipad view remember if you apply constraints on wAnyhAny dimension they will effect all resolutions and devices but in wRegular*hRegular constraints will only effect ipad and landscap views.Mohamedmohammad
@Tessie can you add your code to git and share i can look into it for solution ?Mohamedmohammad
Here you go I created an example project with the size classes in there. I just tested it on the iPhone 6 emulator. When I use the standard view controller it works without problems. When I use the rootviewcontroller on the initial view it gets messed up. github.com/MaikoHermans/sizeClasses.gitTessie

© 2022 - 2024 — McMap. All rights reserved.