Different size classes for iPad portrait and lands

2019-05-17 16:48发布

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

3条回答
Viruses.
2楼-- · 2019-05-17 17:31

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
}
查看更多
来,给爷笑一个
3楼-- · 2019-05-17 17:36

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.

查看更多
Fickle 薄情
4楼-- · 2019-05-17 17:43

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.

查看更多
登录 后发表回答