Our project runs for all iPAD's and we came across a problem as an example we have 8 buttons vertically sitting on a screen with constraints being added as vertical spacing they look fine on a iPAD 9.7 inch, but they look really big on iPAD 12.9, so the question is, is there any good way to actually use the screen space for something better, as in add an extra UIView if it is iPAD 12.9. I have looked into working with size classes, but I believe there is one size class for all iPADs, what I want is if there is a way to have different UI for different iPAD sizes using the Interface builder
The way I imagine your situation is that this specific ViewController has a lot of shared stuff, (like a common top bar, or a navigation bar) but just the middle content doesn't seem to fit properly.
In cases like this it is recommended to have a custom UIView that will load a different xib file based on the height or width of the current device.
The key point here is that, you actually only need one UIView subclass.
For this you can use @IBDesignable as well to preview it in real time inside the interface builder.
To achieve this you have to follow the next steps.
1) Create a .xib file for each of your "UIViews" based on the sizes.
2) Create an UIView subclass.
3) Hook the properties from the interface builder to this subclass. Note that you have to repeat this process for each of the xib files you want to use. IMPORTANT: Even though they are different xibs, they all get hooked into the same class.
4) Mark the created class as @IBDesignable like this.
@IBDesignable class CustomView: UIView {
...
}
5) Add the following code inside your class that will load a different xib based on whatever criteria you chose.
////////// View Logic //////////
// Our custom view from the XIB file
var view: UIView!
func xibSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
}
func setup()
{
// Extra setup goes here
}
func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib : UINib
let screenRect : CGRect = UIScreen.main.bounds;
// Use a different Nib based on the current screen height
if screenRect.size.height == 1024 {
// iPad Air & Pro
nib = UINib(nibName: "iPadNormal", bundle: bundle)
}
else if screenRect.size.height == 1366 {
// Large iPad Pro
nib = UINib(nibName: "iPadLarge", bundle: bundle)
}
else {
// Fall back
nib = UINib(nibName: "iPadFallback", bundle: bundle)
}
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
override init(frame: CGRect) {
// 1. setup any properties here
// 2. call super.init(frame:)
super.init(frame: frame)
// 3. Setup view from .xib file
xibSetup()
// 4. Other Setup
setup()
}
required init?(coder aDecoder: NSCoder) {
// 1. setup any properties here
// 2. call super.init(coder:)
super.init(coder: aDecoder)
// 3. Setup view from .xib file
xibSetup()
// 4. Other Setup
setup()
}
////////////////
IMPORTANT:
This approach is ONLY recommended when the contents of the custom view are the same, or with very minimal changes (layout doesn't matter). If the contents change a lot between sizes (like you actually wanna display different things) then you should create a "BaseViewController" with your shared logic, and make a subclass per iPad Size, so that each of them has it's own ViewController + Interface Builder Screen. Then just load the required screen just as if it was a completely different screen.