Я сделал вид с двумя возможными нижними листами. Действие работает, и нижние листы открываются. Сумасшествие в том, что они открываются без вида внутрь. Я должен закрыть тот, который я открыл, и открыть другой. Когда я это сделаю и вернусь к первому, я увижу содержимое. Код собирается без предупреждений:
LogInView — где логика:
import SwiftUI
struct LogInView: View {
@EnvironmentObject var userInfo: UserInfo
enum Action{
case resetPW, signUp
}
@State private var showSheet = false
@State private var action:Action?
var body: some View {
LoginEmailView(showSheet: $showSheet, action: $action)
.sheet(isPresented: $showSheet){
if self.action == .resetPW{
ModalResetPWView()
}else if self.action == .signUp{
ModalSignUpView()
}
}
}
}
Вид, из которого исходят действия:
import SwiftUI
struct LoginEmailView: View {
@EnvironmentObject var userInfo: UserInfo
@StateObject var user:LogInViewModel = LogInViewModel()
// ----- > THERE IS BINDING
@Binding var showSheet: Bool
@Binding var action:LogInView.Action?
// ----- >
var body: some View {
VStack{
Spacer()
Image("logo")
HStack{
Text("Adres email:")
.padding(.horizontal, 10)
.font(.title)
.foregroundColor(.black)
Spacer()
}
TextField("Enter e-mail adress", text: self.$user.email)
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
.padding(.horizontal, 10)
.keyboardType(.emailAddress)
HStack{
Text("Password:")
.padding(.horizontal, 10)
.font(.title)
.foregroundColor(.black)
Spacer()
}
SecureField("Enter password", text: self.$user.password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
.padding(.horizontal,10)
HStack{
Spacer()
// ----- > First Bottom sheet
Button(action: {
self.action = .resetPW
self.showSheet = true
}) {
Text("Forgot Password")
}
.padding(.top, 5)
.padding(.trailing, 10)
// ----- >
}
Button(action: {
self.userInfo.isAuthenticated = .signedIn
}) {
Text("Log in")
}
.font(.title)
.padding(5)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
.padding(.top, 10)
.opacity(user.isLogInComplete ? 1 : 0.7)
.disabled(!user.isLogInComplete)
// ----- > Second bottom sheet
Button(action: {
self.action = .signUp
self.showSheet = true
}) {
Text("Sign Up")
}
// ----- >
.padding(.top, 35)
Spacer()
}
}
}
@niksarno Да, это помогает! Но: swift var body: some View { LoginEmailView(showSheet: $showSheet, action: $action) .sheet(isPresented: $showSheet){ if self.action == .resetPW{ ModalResetPWView() }else { ModalSignUpView() } } }
Теперь оба BottomSheets впервые показывают подписку :( Почему при первом запуске nil - есть действие, пройденное с открытием нижнего листа
Отвечает ли это на ваш вопрос? Несколько листов(isPresented:) не работают в SwiftUI
Модификатор .sheet создаст представление листа, как только будет инициализирован LogInView(). В вашем утверждении «if.. else if..» нет логики для улавливания «иначе» ситуаций (ситуаций, когда действие == nil). Следовательно, поскольку action == nil в init(), первый .sheet, который будет представлен, не выполнит ваш 'if..else if', и будет представлен EmptyView.
Но не волнуйтесь! Это распространенная проблема, и ее можно легко решить. Вот 2 простых способа реализовать методы, чтобы исправить это (я предпочитаю второй метод, потому что он чище):
МЕТОД 1: представьте одно представление и измените содержимое этого представления вместо того, чтобы переключаться между представлениями для представления.
Вместо того, чтобы выполнять оператор if.. else if.. в модификаторе .sheet, представьте статическое представление (я назвал его SecondaryView), которое имеет переменную @Binding, связанную с вашим действием. Таким образом, когда появляется LogInView(), мы можем гарантировать, что он обязательно отобразит это представление, а затем мы можем просто изменить содержимое этого представления, изменив действие @Binding.
import SwiftUI
struct LogInView: View {
enum Action{
case resetPW, signUp
}
@State private var showSheet = false
@State private var action: Action?
var body: some View {
LoginEmailView(showSheet: $showSheet, action: $action)
.sheet(isPresented: $showSheet) {
SecondaryView(action: $action)
}
}
}
struct LoginEmailView: View {
@Binding var showSheet: Bool
@Binding var action: LogInView.Action?
var body: some View {
VStack(spacing: 40 ){
Text("Forgot Password")
.onTapGesture {
action = .resetPW
showSheet.toggle()
}
Text("Sign Up")
.onTapGesture {
action = .signUp
showSheet.toggle()
}
}
}
}
struct SecondaryView: View {
@Binding var action: LogInView.Action?
var body: some View {
if action == .signUp {
Text("SIGN UP VIEW HERE")
} else {
Text("FORGOT PASSWORD VIEW HERE")
}
}
}
МЕТОД 2: Сделайте каждую кнопку собственным представлением, чтобы она могла иметь свой собственный модификатор .sheet.
В SwiftUI мы ограничены одним модификатором .sheet() на представление. Тем не менее, мы всегда можем добавить представления внутри представлений, и тогда каждому подпредставлению также разрешен собственный модификатор .sheet(). Таким образом, простое решение состоит в том, чтобы сделать каждую из ваших кнопок отдельным представлением. Я предпочитаю этот метод, потому что нам больше не нужно передавать переменные @State/@Binding между представлениями.
struct LogInView: View {
var body: some View {
LoginEmailView()
}
}
struct LoginEmailView: View {
var body: some View {
VStack(spacing: 40 ){
ForgotPasswordButton()
SignUpButton()
}
}
}
struct ForgotPasswordButton: View {
@State var showSheet: Bool = false
var body: some View {
Text("Forgot Password")
.onTapGesture {
showSheet.toggle()
}
.sheet(isPresented: $showSheet, content: {
Text("FORGOT PASSWORD VIEW HERE")
})
}
}
struct SignUpButton: View {
@State var showSheet: Bool = false
var body: some View {
Text("Sign Up")
.onTapGesture {
showSheet.toggle()
}
.sheet(isPresented: $showSheet, content: {
Text("SIGN UP VIEW HERE")
})
}
}
Внутри .sheet ваш оператор «if..else if» не улавливает «else» (ситуации, когда действие == nil). Вероятно, он возвращает EmptyView() на основе этого оператора if.