Apple Watch 和 iPhone 上使用 SwiftUI 的设备特定布局

Device-specific Layout with SwiftUI on Apple Watch and iPhone

有时,我需要对布局进行特定于设备的调整。例如,我可能需要在较小屏幕的 iPhone 上减少间距或在最大屏幕上增加间距。使用 UIKit(甚至 Interface Builder)可以很容易地为特定尺寸 类 设置布局异常。 使用 SwiftUI 进行条件设备特定布局的最佳方法是什么?

我一直在搜索 SwiftUI 文档,但没有找到在布局中访问和使用此类信息的方法。

下面是 Apple Watch 应用程序的示例。根据 Apple 的设计指南,我在 40mm Series 4 的左右两侧添加了 8.5 点的填充。但是,44mm 应该有 9.5 点的填充,任何早于 Series 4 的 Apple Watch 都应该没有填充。

使用 SwiftUI 实现此目的的最佳方法是什么?

struct ContentView : View {

    var body: some View {
        HStack {
            Text("Hello World")
        }.padding([.horizontal], 8.5)
    }
}

一般来说,您可以使用两种方法来实现特定于设备的布局:

  1. 大小 类 通过 @Environment 变量
  2. GeometryReader 更多 fine-grained 控制

遗憾的是,UserInterfaceSizeClass 只有 .compact.regular,在 watchOS 上不可用。

使用环境:

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

要使用 GeometryReader:

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

供参考,以下是手表分辨率:

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

除以 2.0 得到它们的值 points 而不是 pixels

对于iPhone,我可以使用这样的环境:

@Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?

然后在 var body: some View 中,我这样做是为了处理图像如何根据屏幕尺寸缩放。在 iPad 和 iPhone X 及更大范围内进行了一系列测试。我敢肯定还有其他方法。这至少是一种在 SwiftUI 中使用 size 类 的方法。关于如何使用大小 类 的信息还不多。

Image("logo")
      .opacity(1.0)
      .scaleEffect(makeCircleTextBig ? (horizontalSizeClass == .compact ? 0.18 : 0.25) : (horizontalSizeClass == .compact ? 0.06 : 0.1))
      .animation(.easeIn(duration: 1.0))

另请查看 ControlSize: Apple Docs ControlSize

并检查这个不同的方法: Hacking With Swift: SwiftUI size classes

@gohnjanotis,不确定是否为时已晚,但您是否尝试在 GeometryReader 前面添加一个 return?当我在实际创建视图之前使用某些条件时,我经常会遇到该错误。所以它应该如下所示:

var body: some View {
        return GeometryReader { proxy in
          if proxy.size.width > 324.0/2.0 { // 40mm watch resolution in points
            Text("BIG view here")
          } else {
            Text("small view here")
          }
        }
    }