[英]SwiftUI - How to close the sheet view, while dismissing that view
我想實現function。 例如,來自 Apple 的“查找”視圖。
我的目標是當工作表視圖通過導航推送另一個視圖時,用戶可以點擊導航項按鈕來關閉工作表視圖。 就像,下面這個gif。
我嘗試實現這個 function。
我發現一個問題是當用戶點擊“完成”按鈕時。 該應用程序不會關閉工作表視圖。 它只會將視圖彈出到父視圖。 就像,下面這個gif。
這是我的代碼。
import SwiftUI
struct ContentView: View {
@State var isShowSheet = false
var body: some View {
Button(action: {
self.isShowSheet.toggle()
}) {
Text("Tap to show the sheet")
}.sheet(isPresented: $isShowSheet) {
NavView()
}
}
}
struct NavView: View {
var body: some View {
NavigationView {
NavigationLink(destination: NavSubView()) {
Text("Enter Sub View")
}
} .navigationViewStyle(StackNavigationViewStyle())
}
}
struct NavSubView: View {
@Environment(\.presentationMode) var presentationMode
var body: some View {
Text("Hello")
.navigationBarItems(trailing:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}){
Text("Done")
}
)
}
}
我是如何實現這個 function 的? :) 請幫助我,謝謝。 :)
由於工作表中的導航可能足夠長並且關閉不能在所有導航子視圖中,我更喜歡使用環境來僅在需要的地方指定關閉功能,而不是通過所有導航堆棧傳遞綁定。
這是可能的方法(使用 Xcode 11.2 / iOS 13.2 測試)
1)定義環境鍵來存儲工作表狀態
struct ShowingSheetKey: EnvironmentKey {
static let defaultValue: Binding<Bool>? = nil
}
extension EnvironmentValues {
var showingSheet: Binding<Bool>? {
get { self[ShowingSheetKey.self] }
set { self[ShowingSheetKey.self] = newValue }
}
}
2) 將此環境值設置為工作表內容的根目錄,以便在聲明時可在任何子視圖中使用
}.sheet(isPresented: $isShowSheet) {
NavView()
.environment(\.showingSheet, self.$isShowSheet)
}
3)僅在將要使用的子視圖中聲明和使用環境值
struct NavSubView: View {
@Environment(\.showingSheet) var showingSheet
var body: some View {
Text("Hello")
.navigationBarItems(trailing:
Button("Done") {
self.showingSheet?.wrappedValue = false
}
)
}
}
我從來沒有嘗試過 SwiftUI,但我來自 UIKit + RxSwift,所以我有點知道綁定是如何工作的。 我從 SwiftUI 教程中閱讀了很多示例代碼,您關閉模態的方式實際上是正確的,但顯然不適用於導航堆棧。
我剛剛學到的一種方法是使用@Binding
var。 這可能不是最好的解決方案,但它奏效了!
所以你的ContentView
有這個$isShowSheet
。 傳遞對象到你的NavView
通過聲明的一個變量結構NavView
。
內容視圖
.....
}.sheet(isPresented: $isShowSheet) {
NavView(isShowSheet: self.$isShowSheet)
}
導航視圖
struct NavView: View {
@Binding var isShowSheet: Bool
var body: some View {
NavigationView {
NavigationLink(destination: NavSubView(isShowSheet: self.$isShowSheet)) {
Text("Enter Sub View")
}
} .navigationViewStyle(StackNavigationViewStyle())
}
}
最后,對你的子視圖做同樣的事情。
導航子視圖
struct NavSubView: View {
@Environment(\.presentationMode) var presentationMode
@Binding var isShowSheet: Bool
var body: some View {
Text("Hello")
.navigationBarItems(trailing:
Button(action: {
//self.presentationMode.projectedValue.wrappedValue.dismiss()
self.isShowSheet = false
}){
Text("Done")
}
)
}
}
現在您可以看到,您只需isShowSheet
綁定 var - false
發送一個新信號。
self.isShowSheet = false
瞧!
這在 iOS 15 現在要簡單得多。
只需添加:
@Environment(\.dismiss) var dismiss
然后調用:
dismiss()
這是上面 Asperi 代碼的改進版本,因為他們不接受我的編輯。 主要功勞歸於他們。
由於工作表中的導航可能足夠長並且關閉可能不是在所有導航子視圖中,我更喜歡使用環境來僅在需要的地方指定關閉功能,而不是通過所有導航堆棧傳遞綁定。
這是可能的方法(用 Xcode 13 / iOS 15 測試)
定義存儲表的環境密鑰 state
struct ShowingSheetKey: EnvironmentKey { static let defaultValue: Binding<Bool>? = nil } extension EnvironmentValues { var isShowingSheet: Binding<Bool>? { get { self[ShowingSheetKey.self] } set { self[ShowingSheetKey.self] = newValue } } }
將此環境值設置為工作表內容的根,因此在聲明時它將在任何子視圖中可用
@State var isShowingSheet = false... Button("open sheet") { isShowingSheet?.wrappedValue = true } // note no $ in front of isShowingSheet.sheet(isPresented: isShowingSheet?? .constant(false)) { NavView().environment(\.isShowingSheet, self.$isShowingSheet) }
僅在將要使用的子視圖中聲明和使用環境值
struct NavSubView: View { @Environment(\.isShowingSheet) var isShowingSheet var body: some View { Text("Hello").navigationBarItems(trailing: Button("Done") { isShowingSheet?.wrappedValue = false } ) } }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.