iOS 16.4,SwiftUI 底部工作表有时会忽略presentationDetents

问题描述 投票:0回答:1

从 SwiftUI 中的 iOS 16.4 开始,我们可以使用

.sheet
修饰符和
.presentationDetents
来指定底部工作表的高度。我们可以进一步使用
.presentationBackgroundInteraction
来允许与工作表后面的视图进行交互。

我遇到了一个在我看来像是 SwiftUI bug 的问题。

您可以将此代码粘贴到游乐场中以查看实际的错误行为(这是我存在问题的实际应用程序的简化版本)。

错误在于,有时从一个选择更改为另一个选择时,工作表完全忽略

.presentationDetents
.presentationBackgroundInteraction
修饰符。它只是显示为全高模态,没有任何背景交互。

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    let choices = [nil, "One", "Two", "Three"]
    @State var selection: String?
    
    var body: some View {
        VStack {
            Picker("Choose", selection: $selection) {
                ForEach(choices, id: \.self) { choice in
                    Text(choice ?? "None")
                        .tag(choice)
                }
            }
            .padding()
            
            Spacer()
        }
        .pickerStyle(.segmented)
        .sheet(item: $selection) { choice in
            Text("Item selected: \(choice)")
                .presentationDetents([.medium])
                .presentationBackgroundInteraction(
                    .enabled(upThrough: .medium)
                )
        }
    }
}

extension String: Identifiable {
    public var id: String { self }
}

PlaygroundPage.current.setLiveView(ContentView().frame(width: 320, height: 568))

以下是一些截图:

无模态 正确的模态 越野车模态

观察

  1. 在选择另一个选项之前隐藏工作表(通过点击“无”)从不会出现该错误。
  2. 从一个选择跳转到另一个选择有时(但并非总是)会出现错误,例如直接从“一”跳到“二”。
  3. 我的实际应用程序没有使用
    PickerView
    ,所以与此无关。
  4. 我假设它忽略了
    presentationBackgroundInteraction
    ,因为它已经超过了
    .medium
    并达到了最高高度。

因此,在更改为另一个选择之前,工作表的选择没有通过零状态似乎是一个问题,这对我来说是一件完全有效的事情(我不希望工作表消失然后重新出现) .

假设这是一个实际的错误,有什么想法可以解决它吗?我真的不想为应该在本机工作的东西编写或导入第三方库。

预先感谢您的任何见解!

ios swiftui bottom-sheet
1个回答
0
投票

如果您不希望工作表消失并重新出现,我认为您不能使用

sheet(item:)
。即使修复了
presentationDetents
错误,我认为
sheet(item:)
的预期行为仍然是在项目更改时“关闭该工作表,然后显示另一个工作表”。

请使用

sheet(isPresented:)
代替。只要选择不为零,就显示工作表。

.sheet(isPresented: isNotNil($selection)) {
    if let selection {
        Text("Item selected: \(selection)")
            .presentationDetents([.medium])
            .presentationBackgroundInteraction(.enabled(upThrough: .medium))
    }
}
func isNotNil<T>(_ binding: Binding<T?>) -> Binding<Bool> {
    Binding {
        binding.wrappedValue != nil
    } set: { notNil in
        if !notNil {
            binding.wrappedValue = nil
        }
    }
}

如果您不介意工作表消失并再次出现,您可以添加单独的

@State
用于预设工作表。当
nil
更改时,将该状态设置为中间
selection
值。

@State var sheetItem: String?
.onChange(of: selection) { x in
    sheetItem = nil
    DispatchQueue.main.async {
        sheetItem = x
    }
}
.sheet(item: $selection) { choice in ... }
© www.soinside.com 2019 - 2024. All rights reserved.