Different size classes for iPad portrait and lands

2019-05-17 17:30发布

问题:

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.

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

While it should look like this in portrait mode

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.

I hope this shows everything that is needed.

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

回答1:

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
}


回答2:

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.



回答3:

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.