iPad Landscape and Portrait different layouts with Size Class
Asked Answered
D

4

27

How to design iPad Landscape and Portrait screens with different Layouts using Size class. I could find only w-regular and h-regular for both orientations. Example: I need to align 2 views vertically in portrait and horizontally in landscape using Size Class

Delladelle answered 30/12, 2014 at 6:9 Comment(3)
For iphone it is possible to create 2 layouts for different orientations using size class. How can we achieve this for iPad using Size Class and Autolayout ?Delladelle
Actually this is in fact a specific question. And no Apple did not design size classes to enable an iPad landscape specific size class, which makes absolutely no sense to me since you then have to manually deal with landscape in code. I do not agree with some of the approaches that hack the size class system. Just deal with it in code.Percheron
Which way should be better to follow if ipad design for both orientation is totally different? should we need to go with AutoLayout or two different storyboard?Rafflesia
D
6

Finally I found a solution :

if traitCollection.verticalSizeClass == .Regular && traitCollection.horizontalSizeClass == .Regular {

     var orientation:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation;
     if orientation == UIInterfaceOrientation.LandscapeLeft || orientation == UIInterfaceOrientation.LandscapeRight {
            // orientation is landscape


     }  else {
            // orientation is portrait

     }
}
Diacid answered 15/1, 2015 at 21:40 Comment(0)
G
6

It appears to be Apple's intent to treat both iPad orientations as the same -- but as a number of us are finding, there are very legitimate design reasons to want to vary the UI layout for iPad Portrait vs. iPad Landscape.

However, please see this answer for another approach to adapting size classes to do what we need: https://mcmap.net/q/138959/-sizing-class-for-ipad-portrait-and-landscape-modes

Gastrointestinal answered 6/2, 2015 at 6:50 Comment(1)
I am Developing Universal App, In which I tried your approach. it worked well for iPad but when I set constraints for w:Any, h:Any I am getting Unable to simultaneously satisfy constraints. errorAnnulation
M
5

For Swift 3 it would look like this:

override func overrideTraitCollection(forChildViewController childViewController: UIViewController) -> UITraitCollection? {
    if UI_USER_INTERFACE_IDIOM() == .pad &&
        view.bounds.width > view.bounds.height {

        let collections = [UITraitCollection(horizontalSizeClass: .regular),
                           UITraitCollection(verticalSizeClass: .compact)]
        return UITraitCollection(traitsFrom: collections)

    }

    return super.overrideTraitCollection(forChildViewController: childViewController)
}

It will use wRhC instead of wRhR for iPad devices in landscape mode. Put this code to your base view controller, i.e. this rule will work for all controllers that were presented by this one. You can put any additional conditions here... For example, if you want this rule to be working only for specific view controller, your if operator would look like this:

    if UI_USER_INTERFACE_IDIOM() == .pad &&
        childViewController is YourSpecificViewController &&
        view.bounds.width > view.bounds.height {

        let collections = [UITraitCollection(horizontalSizeClass: .regular),
                           UITraitCollection(verticalSizeClass: .compact)]
        return UITraitCollection(traitsFrom: collections)

    }
Myramyrah answered 23/9, 2016 at 7:55 Comment(1)
You may find unintended consequences doing this. For example, if this view controller shows another modal view controller as a Form Sheet, it will show like it does on an iPhone - full screen in portrait - which is probably not what you want. Furthermore, while it is open, if you rotate to landscape it will go back to non-full screen, and will stay that way when you rotate back to portrait. Not a pleasant experience.Surinam
S
2

Swift 4

override func overrideTraitCollection(forChildViewController childViewController: UIViewController) -> UITraitCollection? {
    if UIDevice.current.userInterfaceIdiom == .pad && UIDevice.current.orientation.isLandscape {
        return UITraitCollection(traitsFrom:[UITraitCollection(verticalSizeClass: .compact), UITraitCollection(horizontalSizeClass: .regular)])
    }
    return super.overrideTraitCollection(forChildViewController: childViewController)
}

I like to create a custom subclass of navigationController and then set a storyboards initial Navigation controller to that class. You can also do something similar with a ViewController.

Example:

import UIKit

class NavigationControllerWithTraitOverride: UINavigationController {
    
    // If you make a navigationController a member of this class the descendentVCs of that navigationController will have their trait collection overridden with compact vertical size class if the user is on an iPad and the device is horizontal.
    
    override func overrideTraitCollection(forChildViewController childViewController: UIViewController) -> UITraitCollection? {
        if UIDevice.current.userInterfaceIdiom == .pad && UIDevice.current.orientation.isLandscape {
            return UITraitCollection(traitsFrom:[UITraitCollection(verticalSizeClass: .compact), UITraitCollection(horizontalSizeClass: .regular)])
        }
        return super.overrideTraitCollection(forChildViewController: childViewController)
    }
}

Note: You should not override traitCollection as per the docs

Important

Use the traitCollection property directly. Do not override it. Do not provide a custom implementation.

Selfrenunciation answered 20/4, 2018 at 19:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.