使工作表的大小与内部内容的大小完全相同

Rah*_*Bir 16 swift swiftui swiftui-sheet

假设我在工作表中有一个自定义视图,如下所示

VStack {
   Text("Title")
   Text("Some very long text ...")
}
.padding()
.presentationDetents([.height(250)])
Run Code Online (Sandbox Code Playgroud)

如何获取 VStack 的准确高度并将其传递给presentationDetents 修改器,以便工作表的高度恰好等于内部内容的高度?

Rah*_*Bir 18

使用@jnpdx提出的一般想法,包括一些更新,例如读取覆盖层的大小而不是背景,以下是对我有用的方法:

struct ContentView: View {
    @State private var showSheet = false
    @State private var sheetHeight: CGFloat = .zero

    var body: some View {
        Button("Open sheet") {
            showSheet = true
        }
        .sheet(isPresented: $showSheet) {
            VStack {
                Text("Title")
                Text("Some very long text ...")
            }
            .padding()
            .overlay {
                GeometryReader { geometry in
                    Color.clear.preference(key: InnerHeightPreferenceKey.self, value: geometry.size.height)
                }
            }
            .onPreferenceChange(InnerHeightPreferenceKey.self) { newHeight in
                sheetHeight = newHeight
            }
            .presentationDetents([.height(sheetHeight)])
        }
    }
}

struct InnerHeightPreferenceKey: PreferenceKey {
    static let defaultValue: CGFloat = .zero
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么覆盖层优于背景? (3认同)
  • 我的 TextView 遇到了问题,因为我的文本太长,而此解决方案将其强制为一行。简单的修复方法是将:`.fixedSize(horizo​​ntal: false,vertical: true)` 添加到您可能需要自动计算其高度的任何 TextView (2认同)

小智 10

1. \xd0\xa1创建一个 \xd0\xa1ustom 修饰符,返回任何视图的高度(这是一个非常有用的修饰符,您很可能会在其他地方使用):

\n
struct GetHeightModifier: ViewModifier {\n    @Binding var height: CGFloat\n\n    func body(content: Content) -> some View {\n        content.background(\n            GeometryReader { geo -> Color in\n                DispatchQueue.main.async {\n                    height = geo.size.height\n                }\n                return Color.clear\n            }\n        )\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

2. 使用自定义修改器获取高度。

\n
struct ContentView: View {\n    @State private var showSheet = false\n    @State private var sheetHeight: CGFloat = .zero\n\n    var body: some View {\n        Button("Open sheet") {\n            showSheet = true\n        }\n        .sheet(isPresented: $showSheet) {\n            VStack {\n                Text("Title")\n                Text("Some very long text ...")\n            }\n            .padding()\n            .fixedSize(horizontal: false, vertical: true)\n            .modifier(GetHeightModifier(height: $sheetHeight))\n            .presentationDetents([.height(sheetHeight)])\n        }\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n


jn_*_*pdx 6

您可以使用GeometryReaderPreferenceKey读取大小,然后将其写入状态变量。在我的示例中,我存储了整个尺寸,但您可以调整它以仅存储高度,因为这可能是您需要的唯一参数。

struct ContentView: View {
    @State private var showSheet = false
    @State private var size: CGSize = .zero
    
    var body: some View {
        Button("View sheet") {
            showSheet = true
        }
        .sheet(isPresented: $showSheet) {
            VStack {
                Text("Title")
                Text("Some very long text ...")
            }
            .padding()
            .background(
                GeometryReader { geometryProxy in
                    Color.clear
                        .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
                }
            )
            .onPreferenceChange(SizePreferenceKey.self) { newSize in
                size.height = newSize.height
            }
            .presentationDetents([.height(size.height)])
        }
    }
}

struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() }
}

Run Code Online (Sandbox Code Playgroud)