【问题标题】:Device-specific Layout with SwiftUI on Apple Watch and iPhone在 Apple Watch 和 iPhone 上使用 SwiftUI 进行设备特定布局
【发布时间】:2019-11-15 13:37:12
【问题描述】:

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

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

以下是 Apple Watch 应用的示例。根据 Apple 的设计指南,我在 40 毫米系列 4 的左侧和右侧添加了 8.5 个填充点。但是,44 毫米应该有 9.5 个填充点,任何比系列 4 更早的 Apple Watch 都应该没有填充。

使用 SwiftUI 实现这一目标的最佳方法是什么?

struct ContentView : View {

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

【问题讨论】:

    标签: ios apple-watch swiftui watchos


    【解决方案1】:

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

    1. 通过@Environment 变量调整类的大小
    2. GeometryReader 进行更细粒度的控制

    很遗憾,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 中获得它们的值。

    【讨论】:

    • 当我尝试使用 GeometryReader 方式时,我收到一条错误消息,上面写着The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions,但我无法构建它。 (Xcode 11.0 beta 3)关于如何克服这个问题的任何想法,或者可能只是一个 Xcode 错误?
    • 对于GeometryReader 的有效代码,我遇到了很多编译器错误。一种解决方法是将内容放在像func mySizedContent(_ proxy: GeometryProxy) -> some View { ... } 这样的函数中。
    • 当我包装 GeometryReader 时,我收到一个错误,在 GeometryReader 闭包的开头显示 Unable to infer complex closure return type; add explicit type to disambiguate,但我不确定我是否足够了解 Swift 和Swift UI 找出需要指定的内容才能使其编译。
    • 对答案的小修正:分辨率为@2x。代理返回 1x 的值。所以它应该像 proxy.size.width > 324/2
    【解决方案2】:

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

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

    然后在 var body: some View 中,我这样做是为了处理图像如何根据屏幕尺寸进行缩放。在 iPad 和 iPhone X 及更大的设备上进行了大量测试。我敢肯定还有其他方法。这至少是在 SwiftUI 中使用尺寸类的一种方式。目前还没有太多关于如何使用尺寸等级的信息。

    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

    【讨论】:

      【解决方案3】:

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

      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")
                }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-14
        • 1970-01-01
        • 1970-01-01
        • 2020-07-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多