Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Device-specific Layout with SwiftUI on Apple Watch and iPhone

Sometimes, I need to make device-specific adjustments to layouts. For example, I may need to reduce spacing on an iPhone with a smaller screen or increase spacing on the largest screens. With UIKit (and even Interface Builder) it was easy to make layout exceptions for specific size classes. What is the best way to do conditional device-specific layouts with SwiftUI?

I've been scouring the SwiftUI documentation, and haven't found a way to access and use this type of information in layouts.

Below is an example for an Apple Watch app. Per Apple's design guidelines, I'm adding 8.5 points of padding to the left and right on the 40mm Series 4. However, the 44mm should have 9.5 points of padding, and any Apple Watch older than Series 4 should have no padding.

What is the best way to achieve this with SwiftUI?

struct ContentView : View {

    var body: some View {
        HStack {
            Text("Hello World")
        }.padding([.horizontal], 8.5)
    }
}
like image 372
gohnjanotis Avatar asked Jul 04 '19 21:07

gohnjanotis


1 Answers

In general there are two methods you can use to achieve device specific layouts:

  1. Size classes via @Environment variables
  2. GeometryReader for more fine-grained control

Unfortunately, UserInterfaceSizeClass only has .compact and .regular and is not available on watchOS.

To use the environment:

struct MyView: View {
    @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
}

To use GeometryReader:

var body -> some View {
    GeometryReader { proxy in
      if proxy.size.width > 324.0/2.0 { // 40mm watch resolution in points
        MyBigView()
      } else {
        MySmallView()
      }
    }
}

For reference, here are the watch resolutions:

  • 40mm: 394×324
  • 44mm: 448×368
  • 38mm: 340×272
  • 42mm: 390×312

Divide by 2.0 to get their values in points instead of pixels.

like image 81
arsenius Avatar answered Oct 23 '22 01:10

arsenius