0

The Ask: I want to have different layouts between Portrait vs Landscape on the iPad. (I'm successful on the iPhone But iPad share similar size classes)

What I've done/Tried:

Reading and searching thru Google and SO, I haven't found the solution. What I did learn was about overriding UITraitsCollection and If possible, I would like to force the iPad Landscape configuration to follow the same one which I've already set up for the iPhone Landscape mode using hCompact

I tried this solution https://stackoverflow.com/a/60409218/14414215 but unsure where to put it and when just placed within the UIViewController, when running, the app doesn't even call it. (It's likely cos I don't have my views within a childViewController?)

This post here also references UITraitsCollection https://stackoverflow.com/a/41374705/14414215 however there is a lack of an example.

I'm fairly sure that this is something that many apps are doing but I'm not able to find the solution.

For reference: This is what I want to achieve on the iPad as well. (iPhone works great using this solution from @DonMag)

StackView layout side by side & on Top of each other (like zStack)

app4g
  • 670
  • 4
  • 24

1 Answers1

1

With different device screen aspect ratios, and the multi-tasking capabilities on iPads, you're encouraged to think in terms of size not orientation.

If your app is being run with Slide Over / Split View, the size class can be wC hR even when the device is in "landscape orientation."

If you want to change layout based on aspect ratio:

  • if width > height use a "landscape" layout
  • if height > width use a "portrait" layout

You may want to create your own constraint collections and activate / deactivate them in viewWillTransition(to size:...)

If you want to stick with Trait variations, you'll run into problems trying to manipulate them for the "root" view of a controller.

You could try making your controller a child view controller, either by embedding it in a UIContainerView or adding it via code, and then implementing (in the "parent" view controller):

class ParentViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let vc = storyboard?.instantiateViewController(withIdentifier: "myVC") as? MyRealViewController {
            addChild(vc)
            view.addSubview(vc.view)
            vc.didMove(toParent: self)
        }
        
    }
    
    override func overrideTraitCollection(forChild childViewController: UIViewController) -> UITraitCollection? {
        if childViewController.view.bounds.width > childViewController.view.bounds.height {
            let collections = [UITraitCollection(horizontalSizeClass: .regular),
                               UITraitCollection(verticalSizeClass: .compact)]
            return UITraitCollection(traitsFrom: collections)
        }
        return super.overrideTraitCollection(forChild: childViewController)
    }
    
}
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • I'm not set on using trait variations, but would using ```viewWIllTransition``` enable the use of Storyboard/IB instead of doing the layout via code? I'm keen on using the aspect ratio suggestion, but I'm still wondering if it'll be as simple as "if width>height then use same aspect ratio as iPhone landscape" (but of course I'm sure that it's not going to be that easy( – app4g Jan 20 '21 at 15:55
  • @myjunk - if you use `viewWillTransition(to size:...)` you'll probably need to create collections of constraints instead of setting trait variations. – DonMag Jan 20 '21 at 16:20