SwiftUI中Form嵌套下Sheet首次弹出后自动消失的问题求助
SwiftUI中Form嵌套下Sheet首次弹出后自动消失的问题求助
大家好,我遇到了一个奇怪的SwiftUI问题,想请各位帮忙看看。
我写了一个OutdoorSection组件,里面包含一个按钮,点击后会弹出LocationPicker的sheet来选择位置。但当这个组件被放在Form里面时,第一次点击“Select”按钮,sheet会弹出来然后立刻消失;第二次及之后点击,sheet就能正常保持打开状态。如果不放在Form里,整个功能就完全正常。
我已经做了两个预览(Form (buggy)和No Form)来复现这个问题,相关代码如下:
OutdoorSection 组件代码
import SwiftUI import CoreLocation struct OutdoorSection: View { @Binding var locationName: String? @Binding var temperature: Double @Binding var relativeHumidity: Double let onLocationChanged: (CLLocationCoordinate2D?) -> Void @State private var showPickerSheet: Bool = false var body: some View { Section(header: Label("Outdoor", systemImage: "cloud.sun.fill")) { VStack { HStack { Label(locationName ?? "", systemImage: "mappin.and.ellipse") Spacer() Button("Select") { showPickerSheet = true } .buttonStyle(.borderless) } TemperatureHumidityInputs(temp: $temperature, rh: $relativeHumidity) } } .sheet(isPresented: $showPickerSheet) { LocationPicker{ name, coordinate in showPickerSheet = false locationName = name onLocationChanged(coordinate) } } } } #Preview("Form (buggy)") { Form { OutdoorSection( locationName: .constant("Berlin"), temperature: .constant(20.0), relativeHumidity: .constant(50.0), onLocationChanged: { _ in } ) } } #Preview("No Form") { OutdoorSection( locationName: .constant("Berlin"), temperature: .constant(20.0), relativeHumidity: .constant(50.0), onLocationChanged: { _ in } ) }
LocationPicker 组件代码
import SwiftUI import MapKit import CoreLocation struct LocationPicker: View { @Environment(\.dismiss) private var dismiss @State var vm = LocationPickerViewModel() /// callback: (placeName, coordinate) or (nil, nil) on reset let onSelect: (String?, CLLocationCoordinate2D?) -> Void var body: some View { NavigationView { VStack { // Input + user-location button HStack { TextField("Enter address…", text: $vm.query) .textFieldStyle(.roundedBorder) Button { vm.requestCurrentLocation() } label: { Image(systemName: "location") .font(.title2) } .disabled(vm.isRequestingLocation) .help("Use current location") } .padding() // Show any location-error if let err = vm.locationError { Text(err) .foregroundColor(.red) .font(.caption) } // Autocomplete list List(vm.suggestions, id: \.self) { suggestion in VStack(alignment: .leading) { Text(suggestion.title) .font(.headline) Text(suggestion.subtitle) .font(.subheadline) .foregroundColor(.secondary) } .contentShape(Rectangle()) .onTapGesture { vm.search(suggestion) { name, coord in onSelect(name, coord) } } } .listStyle(.plain) } .navigationTitle("Pick a Location") .navigationBarTitleDisplayMode(.inline) .toolbar { // Close without callback ToolbarItem(placement: .navigationBarLeading) { Button("Close") { dismiss() } } // Reset means “nil location” ToolbarItem(placement: .navigationBarTrailing) { Button("Reset") { onSelect(nil, nil) } } } } } } #Preview { ZStack{ } .sheet(isPresented: .constant(true)){ LocationPicker { name, coord in print("Selected Location: \(name ?? "Unknown"), Coordinates: \(coord?.latitude ?? 0), \(coord?.longitude ?? 0)") } } }
注:TemperatureHumidityInputs和LocationPickerViewModel的代码我没贴,因为它们不影响这个问题的复现。
我之前和GPT聊过,它建议把showPickerSheet这个状态变量移到OutdoorSection外面,避免重渲染时被重置。我试着用Binding来实现,但没成功。而且我觉得这个状态变量属于OutdoorSection本身,放在父组件里不太符合代码封装的思路。
有没有大佬知道这个问题的根源是什么,或者有没有更好的解决办法?
内容来源于stack exchange
相关产品推荐
相关产品推荐

