【问题标题】:What is UIView readableContentGuide equivalent thing in the SwiftUI什么是 SwiftUI 中的 UIView readableContentGuide 等价物
【发布时间】:2020-09-01 01:34:30
【问题描述】:

UIView 具有readableContentGuide,因此布局可能与屏幕大小相关,并确保内容始终可读。我在 SwiftUI 中找不到关于这些东西的任何信息。

在 SwiftUI 中可以使用什么等效的东西?如果没有,我们可以使用 SwiftUI 组件在 UIKit 中构建相同的效果吗?

谢谢。

【问题讨论】:

    标签: ios layout uikit swiftui


    【解决方案1】:

    在 SwiftUI 中没有直接的 readableContentGuide 替代方案。它应该直接支持到视图中。从理论上讲,SwiftUI 应该应用设备特定的填充,但它不会在 v1.0 中发生。因此,即,将 padding 修饰符添加到 TextField 应该在分辨率中应用更大的填充,例如 12.9 英寸的 iPad。

    即便如此,您也可以编写自己的视图修饰符来应用自定义填充。这是@mecid 完成的示例:

    import SwiftUI
    
    private struct ReadableGuidePadding: ViewModifier {
    
        @Environment(\.horizontalSizeClass) var horizontal
    
        func body(content: Content) -> some View {
           content.padding(.horizontal, horizontal == .regular ? 84: 16)
        }
    
    }
    
    extension View {
    
        func readableGuidePadding() -> some View {
            modifier(ReadableGuidePadding())
        }
    
    }
    
    

    【讨论】:

      【解决方案2】:

      其他解决方案对我不起作用,因为它们依赖于硬编码的填充量或下降到 UIKit,这对于需要在所有不同尺寸的 iPhone 上看起来都很好的多平台 SwiftUI 应用程序来说不是很好、iPad 和 Mac。因此,由于仍然没有原生的 SwiftUI 等价物(从 iOS 15/macOS 12 开始),我想我会做一个替代品。

      我的替代方法是根据以下公式计算填充量:

      • 视图的当前宽度
      • 还有一些理想的可读宽度
      struct ReadabilityPadding: ViewModifier {
          let isEnabled: Bool
          @ScaledMetric private var unit: CGFloat = 20
      
          func body(content: Content) -> some View {
              // Use a GeometryReader here to get view width.
              GeometryReader { geometryProxy in
                  content
                      .padding(.horizontal, padding(for: geometryProxy.size.width))
              }
          }
      
          private func padding(for width: CGFloat) -> CGFloat {
              guard isEnabled else { return 0 }
      
              // The internet seems to think the optimal readable width is 50-75
              // characters wide; I chose 70 here. The `unit` variable is the 
              // approximate size of the system font and is wrapped in
              // @ScaledMetric to better support dynamic type. I assume that 
              // the average character width is half of the size of the font. 
              let idealWidth = 70 * unit / 2
      
              // If the width is already readable then don't apply any padding.
              guard width >= idealWidth else {
                  return 0
              }
      
              // If the width is too large then calculate the padding required
              // on either side until the view's width is readable.
              let padding = round((width - idealWidth) / 2)
              return padding
          }
      }
      

      这是它在不同设备上的外观(顶部是正常的,底部是应用了 ReadabilityPadding 视图修饰符):

      【讨论】:

      • 太棒了!非常感谢。
      • 旋转后布局不会改变是我使用可读布局指南的另一个原因。也许总是将可用宽度限制为 iPad min-width 是有意义的。
      【解决方案3】:

      考虑到设备宽度的无限范围,此处建议的填充解决方案没有意义。我们需要一个解决方案来满足所有类型的设备尺寸,并且可以为内容保留可读的宽度。

      任何视图都可以以 SwiftUI 友好的方式使用最终结果:

      SomeReallyLongView()
          .readableGuidePadding()
      

      首先,我们需要一个ViewModifier,它可以将视图的宽度固定到最大边距。 UIKit 实际上将可读内容宽度定义为 672,所以让我们使用它。

      private struct ReadableGuidePadding: ViewModifier {
          func body(content: Content) -> some View {
              HStack(spacing: 0) {
                  Spacer(minLength: 0)
                  content.frame(maxWidth: 672)
                  Spacer(minLength: 0)
              }
          }
      }
      

      现在我们有了一个修饰符,可以将我们的内容裁剪为 672 点宽,并在需要时使用水平分隔符。请注意,我们使用 0 的 minLength 否则在较小的屏幕上总是会有水平填充。我们不希望这样。

      现在我们可以创建一个方便的视图扩展来使用我们的修饰符:

      extension View {
          func readableGuidePadding() -> some View {
              modifier(ReadableGuidePadding())
          }
      }
      

      享受

      【讨论】:

        【解决方案4】:

        这应该可行:

        
        private struct ReadablePadding: ViewModifier {
          private static let readableAera: CGSize = UIViewController().view.readableContentGuide.layoutFrame.size
          @State var orientation = UIDevice.current.orientation
          @Environment(\.horizontalSizeClass) var horizontalSizeClass
          @Environment(\.verticalSizeClass) var verticalSizeClass
          
          func body(content: Content) -> some View {
            content
              .padding(.horizontal, padding())
              .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
                orientation = UIDevice.current.orientation
              }
          }
          
          private func padding() -> CGFloat {
            var width = horizontalSizeClass == .compact ? min(UIScreen.main.bounds.width, UIScreen.main.bounds.height) :
              max(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
            
            if horizontalSizeClass == .regular, verticalSizeClass == .regular { // iPads
              print(orientation)
              width = UIScreen.main.bounds.width
            }
            
            return (width - ReadablePadding.readableAera.width) / 2 + 16.0 // 16.0 is a margin
          }
        }
        
        extension View {
          func readableGuidePadding() -> some View {
            modifier(ReadablePadding())
          }
        }
        

        【讨论】:

        • 什么是.doubleMargin
        • 对不起,这是一个浮动。 16.0 我刚刚更新了我的答案
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-13
        • 2014-05-08
        • 2014-06-12
        • 1970-01-01
        • 2022-11-28
        • 2021-06-19
        相关资源
        最近更新 更多