【问题标题】:SwiftUI behavior of .frame(height: nil).frame(height: nil) 的 SwiftUI 行为
【发布时间】:2021-02-09 02:22:29
【问题描述】:

问题

我收到一个线程问题,显示“帧尺寸无效(负数或非有限)。”

这是我的代码:

struct CellStyle: ViewModifier {
    func body(content: Content) -> 一些视图 {
        内容
            .frame(宽度:.infinity,高度:56,对齐方式:.center)
            .padding(.horizo​​ntal, 16)
    }
}

代码运行良好,我似乎在做它应该做的事情,所以我很困惑为什么它会给我线程问题。为什么代码会在没有有限宽度/高度的情况下运行,这与 Apple 文档相矛盾? (请参阅下面的“一些阅读”部分)

修复

这段代码很好地解决了这个问题,但我仍然希望我能理解为什么前面的代码不会崩溃或产生错误。

struct CellStyle: ViewModifier {
    func body(content: Content) -> 一些视图 {
        内容
            .frame(高度:56,对齐方式:.center)
            .frame(最大宽度:.infinity)
            .padding(.horizo​​ntal, 16)
    }
}

据我所知,它给了我线程问题,因为我告诉.frame,我想要一个不是有限的宽度,它想要一个有限的宽度。

关于堆栈溢出的其他问题

我发现了两个问同样问题的问题:
iOS 14 Invalid frame dimension (negative or non-finite)

SwiftUI iOS14 GeometryReader Invalid frame dimension

在第一个问题中,线程问题是有道理的,因为给定代码.frame(width: p.size.width - padding),不能保证p.size.width 会小于padding。据我所知,这是一个给定值可能为负的问题。
我遇到的这个问题与给定值不是有限的有关,所以这些问题不相关。
第二个问题还没有回答,有点含糊,所以现在对我没有多大帮助。也许以后有人会给出一个有用的答案,但到目前为止,它还没有帮助。

一些阅读

看着Apple docs我发现了这个:

使用此方法为视图的宽度、高度或两者指定固定大小。如果您只指定其中一个维度,则生成的视图会假定此视图在另一个维度中的大小调整行为。

那么为什么.frame(width: .infinity, height: 56, alignment: .center) 甚至会运行呢?
Apple 所说的“结果视图假定此视图在另一个维度上的大小调整行为”是什么意思?它是否总是假定该视图是“推出”视图,从而给出与 .infinity 相同的结果?

我对此进行了测试并运行了以下代码:

struct CellStyle: ViewModifier {
    func body(content: Content) -> 一些视图 {
        内容
            .frame(高度:56,对齐方式:.center)
            .padding(.horizo​​ntal, 16)
    }
} 

它似乎给出了相同的结果,所以现在我很好奇是否存在快速“假设”宽度会导致 .infinity 以外的行为的情况?

最后一个问题

.frame(width: .infinity).frame(width: nil) 之间的行为差​​异是什么(相当于发射宽度或高度)。

func frame(width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment = .center) -> 一些视图

Apple docs

感谢您的帮助!

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

    尝试 1:- 申请 .frame(width: nil, height: 200, alignment: .center) 不适合我。

    尝试 2:- 申请 .frame(width: .infinity, height: 200, alignment: .center) 对我不起作用。

    尝试 1 和尝试 2 的结果,


    尝试 3 :- (成功) 申请 .frame(minWidth: 0, maxWidth: .infinity) 对我有用。

    尝试 3 的结果

    【讨论】:

      【解决方案2】:

      .frame(width: nil) 做了什么

      基本上 .frame 将采用给定的值并返回另一个使用您输入的值更新的视图。
      如果省略其中一个参数或将其设置为 nil,则它将采用上一个视图的相应宽度/高度值。

      测试代码:

      struct ContentView: View {
          @State var keyValue = ""
          var body: some View {
              VStack(spacing: 10) {
                  Text("Something")
                      .background(Color.blue)
                  
                  Text("Something")
                      .frame(width: 300, height: nil, alignment: .center)
                      .background(Color.blue)
                  
                  Text("Something")
                      .frame(width: nil, height: 200, alignment: .center)
                      .background(Color.blue)
                  
                  Text("Something")
                      .frame(width: nil, height: nil, alignment: .center)
                      .background(Color.blue)
              }
          }
      }
      

      为什么 .frame(width: .infinity) 仍然运行

      .infinity (Apple doc on .infinity) 是Float 类型,所以.frame 没有办法不排除它,但它仍然会产生问题。 (因此线程问题)

      感谢 Mark Moeykens 帮助我得到这个答案!

      注意:.frame(maxWidth: .infinity) 而不是 .frame(width: .infinity)

      【讨论】:

        【解决方案3】:

        因为它是记录在案的接口契约:

        /// - Parameters:
        ///   - width: A fixed width for the resulting view. If `width` is `nil`,
        ///     the resulting view assumes this view's sizing behavior.
        ///   - height: A fixed height for the resulting view. If `height` is `nil`,
        ///     the resulting view assumes this view's sizing behavior.
        ///   - alignment: The alignment of this view inside the resulting view.
        ///     `alignment` applies if this view is smaller than the size given by
        ///     the resulting frame.
        ///
        /// - Returns: A view with fixed dimensions of `width` and `height`, for the
        ///   parameters that are non-`nil`.
        @inlinable public func frame(width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment = .center) -> some View
        

        而具有最小/最大参数的修饰符类型允许灵活的约束(此处未复制 - 读入生成的 SwiftUI 模块)。

        【讨论】:

        • 如果您阅读我在“一些阅读”之后所说的内容,您会发现我明白这一点。让我感到困惑的是为什么将 .infinity 作为宽度或高度仍然会运行,然后如果省略宽度或高度的参数总是会推断宽度/高度像 .infinity 一样被“推出”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-22
        • 1970-01-01
        • 2011-02-20
        相关资源
        最近更新 更多