基于显示 2 选择的工作表视图的 SwiftUI 导航决策
Posted
技术标签:
【中文标题】基于显示 2 选择的工作表视图的 SwiftUI 导航决策【英文标题】:SwiftUI navigation decision based on a sheet view presenting 2 choice 【发布时间】:2021-07-02 19:54:32 【问题描述】:我正在展示一个“向导”,它将检测 BLE 设备,然后如果它是正确的,最后一个视图将询问我们是要注册还是跳过。
编辑: 视图顺序是: MainView 在 fullScreenCover 中显示第一个信息视图,通知如何检测 BLE 设备,然后这个推送第二个视图,其中包含最近的 BLE 设备上的一些信息,正是在这个视图中,我们有我所在的分支出示一张表格,询问用户是要继续注册 BLE 设备还是跳过。
所以 MAIN > INFOView -> BLE detection (> Register or skip ? RegisterView : Destack to main)
我将最后一个视图显示为一张有 2 个按钮的表单,上面提到的第一个显示“注册”,另一个显示“跳过”。如果用户按下注册,那么我们关闭工作表并导航到正在收集个人信息以注册 BLE 设备的视图。另一方面,如果用户选择跳过,那么向导需要解栈回到主视图。
通常在 UIKit 中,如果选择了跳过,我只会让一个代表通知我选择。我会调用 pop 到根视图控制器,否则,如果选择了注册选项,我会关闭工作表视图,然后导航到另一个最终视图并让用户注册。
在 SwiftUI 中,我不知道如何处理导航叉。我尝试使用 PassthroughSubject,但后来我必须将 PassthroughSubject var 设置为状态 var,最后,我只是没有从选择中的发送中得到回调。
尝试绑定然后希望进行 onReceive,但随后它要求发布者,并且为此创建发布者感觉错误。
我想知道在 swiftUI 中处理这个问题的最佳方法是什么?
编辑: 这是显示 BLE 设备(智能自行车)信息的视图的代码(使用 @Predrag Samardzic 的重播更新),将首先推送一个请求以了解用户是否要注册,然后如果是如果不关闭整个堆栈,则推送该注册屏幕。
struct A18BikeDiscoveryView: View
@EnvironmentObject var bleManager: ArgonBLEManager
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
private let shouldShowRegistration = CurrentValueSubject<Bool, Never>(false)
@State var isSheetPresented = false
@State var isRegistrationPresented = false
var body: some View
VStack
NavigationLink(
destination: A18RegistrationQuestionairy(QuestionairyViewModel()),
isActive: $isRegistrationPresented
)
EmptyView()
A18ImageTextBanner(text: NSLocalizedString("bike_discovery_view_title", comment: ""))
.padding(.bottom, 35)
.navigationBarBackButtonHidden(true)
if let value = bleManager.model?.bikeInfo?.bikeModel
Text(value)
.fontWeight(.bold)
.scaledFont(.largeTitle)
Image("subitoBike")
.resizable()
.frame(minWidth: 0334, idealWidth: 334, maxWidth: .infinity, minHeight: 223, idealHeight: 223, maxHeight: .infinity, alignment: .center)
.aspectRatio(contentMode: .fit)
.padding(.bottom, 10)
Divider()
VStack(alignment: .leading)
HStack
Text("bike_discovery_view_year_created")
if let v = bleManager.model?.bikeInfo?.year
Text(v)
HStack
Text("bike_discovery_view_model_size")
Text("\(getSizeFromSerial())")
HStack
Text("bike_discovery_view_bike_serial_number")
if let v = bleManager.model?.bikeInfo?.bikeSerialNumber
Text(v)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 66, alignment: .leading)
.padding(.horizontal, 40)
Divider()
.padding(.bottom, 30)
Button(action:
isSheetPresented = true
, label:
Text("bike_discovery_view_bike_pairing_button_title")
.fontWeight(.bold)
.foregroundColor(.white)
)
.buttonStyle(A18RoundButtonStyle(bgColor: .red))
.padding(.horizontal)
.sheet(
isPresented: $isSheetPresented,
onDismiss:
if shouldShowRegistration.value
isRegistrationPresented = true
,
content:
A18BikeParingSelection(shouldShowRegistration: shouldShowRegistration)
)
.onReceive(shouldShowRegistration) shouldShowRegistration in
isSheetPresented = false
Button(action:
bleManager.disconect()
self.presentationMode.wrappedValue.dismiss()
, label:
Text("bike_discovery_view_bike_pairing_cancel_button_title")
.fontWeight(.bold)
.foregroundColor(Color("grey55"))
)
.padding()
Spacer()
.navigationBarColor(backgroundColor: .white, tintColor: .black)
.navigationBarTitleDisplayMode(.inline)
func getSizeFromSerial() -> String
if let serial = bleManager.model?.bikeInfo?.bikeSerialNumber
if serial.contains("XXS")
return "XXS"
else if serial.contains("XSM")
return "XS"
else if serial.contains("SML")
return "S"
else if serial.contains("MED")
return "M"
else if serial.contains("LAR")
return "L"
return "N/A"
【问题讨论】:
【参考方案1】:这是一种可能的解决方案 - 使用 CurrentValueSubject 来触发关闭并保留有关在显示屏幕上做出的选择的信息。然后,如果需要注册,则在关闭工作表时触发它。
struct MainView: View
private let shouldShowRegistration = CurrentValueSubject<Bool, Never>(false)
@State var isSheetPresented = false
@State var isRegistrationPresented = false
var body: some View
VStack
// this part is if you want to push registration screen, you will need to have MainView inside NavigationView for it
NavigationLink(
destination: RegistrationView(),
isActive: $isRegistrationPresented
)
EmptyView()
// ----------------------------------------------------
Button
isSheetPresented = true
label:
Text("Present sheet")
.sheet(
isPresented: $isSheetPresented,
onDismiss:
if shouldShowRegistration.value
isRegistrationPresented = true
,
content:
ChoiceView(shouldShowRegistration: shouldShowRegistration)
)
.onReceive(shouldShowRegistration) shouldShowRegistration in
isSheetPresented = false
// this part is if you want to present registration screen as sheet
// .sheet(
// isPresented: $isRegistrationPresented,
// content:
// RegistrationView()
// )
struct ChoiceView: View
let shouldShowRegistration: CurrentValueSubject<Bool, Never>
var body: some View
VStack
Button
shouldShowRegistration.send(false)
label:
Text("Dismiss")
Button
shouldShowRegistration.send(true)
label:
Text("Register")
struct RegistrationView: View
var body: some View
Text("Registration")
【讨论】:
感谢您的帖子。它确实可以展示收集用户信息的视图。但是需要解除堆栈的部分不需要。我很难受。可能我仍然对 UIKit 框架的想法太多了。我尝试使用 PresentationMode 将视图堆栈放回主视图,但这不起作用。我会用一些代码更新这篇文章。 我最终为首先出现的视图复制了相同的架构。以上是关于基于显示 2 选择的工作表视图的 SwiftUI 导航决策的主要内容,如果未能解决你的问题,请参考以下文章