How to handle Auto Layout with different screen sizes

Issue #35

Auto Layout is awesome. Just declare the constraints and the views are resized accordingly to their parent ‘s bounds changes. But sometimes it does not look good, because we have fixed values for padding, width, height, and even fixed font size.

Read more How to make Auto Layout more convenient in iOS

This can be solved by some degree using Size Class. The idea of size class is that we have many sets of constraints, and based on the device traits, we enabled some of them. This is more convenient to do in Storyboard (although very hard to reason about), but if we’re doing in code (my prefer way), then it is a lot of code. And a lot of code means a lot of bugs.

If you take a look at iOSRes, we see the ratio 16:9 (height:width)

  • iPhone SE (320 x 568): 1.775
  • iPhone 6 (375 x 667): 1.778
  • iPhone 6+ (414 x 736): 1.778

They mostly have the same ratio. So we can have a simple approach, that scale elements based on ratio. Given the fact that the designer usually designs for iPhone 6 size, we can make that a base.

In this approach, the content will scale up or down depending on its ratio. You may argue that the idea of bigger phone is to display more, not to show the same content bigger. You may be right, in that case you need to create different constraints and different UIs. But if you want simple solutions that work, this is one of them

This is the technique I used when doing Windows Phone development, but it applies to many platforms as well

Calculate the ratio

1
2
3
4
5
6
7
8
class Device {
// Base width in point, use iPhone 6
static let base: CGFloat = 375

static var ratio: CGFloat {
return UIScreen.main.bounds.width / base
}
}

Extension to make it convenient

We can have a computed property called adjusted that adjusts the size based on the ratio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
extension CGFloat {

var adjusted: CGFloat {
return self * Device.ratio
}
}

extension Double {

var adjusted: CGFloat {
return CGFloat(self) * Device.ratio
}
}

extension Int {

var adjusted: CGFloat {
return CGFloat(self) * Device.ratio
}
}

Use the ratio

You can adjust as much as you want

1
2
3
4
5
6
label.font = UIFont.systemFont(ofSize: 23.adjusted)

phoneTextField.leftAnchor.constraint(equalTo: container.leftAnchor, constant: 30.adjusted),
phoneTextField.rightAnchor.constraint(equalTo: container.rightAnchor, constant: -30.adjusted),

imageView.widthAnchor.constraint(equalToConstant: 80.adjusted), imageView.heightAnchor.constraint(equalToConstant: 90.adjusted),

Comments