多个底部工作表 - 内容不会加载 SwiftUI [英] Multiple Bottom sheets - the content doesn't load SwiftUI

查看:21
本文介绍了多个底部工作表 - 内容不会加载 SwiftUI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用两个可能的底部工作表制作了一个视图.该操作有效,并且底部工作表确实打开了.疯狂的事情是他们在没有内部景观的情况下打开.我必须关闭我打开的一个并打开另一个.当我这样做并回到第一个时,我会看到内容.代码构建时没有警告:

I have made a view with two possible bottom sheets. The action works, and Bottom Sheets do open. Crazy thing is they open without the view inside. I have to close the one I opened and open the other one. When I do and than come back to the first one I will see the content. The code builds without warnings:

LogInView - 逻辑在哪里:

LogInView - where the logic is:

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()
        }
        
    }
    
}

推荐答案

.sheet 修饰符将在 LogInView() 初始化后立即创建工作表视图.在您的 'if.. else if..' 语句中,没有逻辑可以捕获 'else' 情况(action == nil 的情况).因此,由于 init() 上的 action == nil,将出现的第一个 .sheet 将使您的if..else if"失败,并且将出现 EmptyView.

The .sheet modifier will create the sheet view as soon as LogInView() is initialized. In your 'if.. else if..' statement, there is no logic to catch 'else' situations (situations where action == nil). Therefore, since action == nil on init(), the first .sheet that will present will fail your 'if..else if' and an EmptyView will present.

但是别担心!这是一个常见问题,很容易解决.这里有两种简单的方法来实现解决这个问题的方法(我更喜欢第二种方法,因为它更干净):

But don't worry! This is a common issue and can be easily solved. Here are 2 easy ways to implement methods to fix this (I prefer the 2nd method bc it's cleaner):

方法 1:呈现单一视图更改该视图的内容,而不是在要显示的视图之间切换.

不要在 .sheet 修饰符中执行 'if.. else if..' 语句,而是呈现一个静态视图(我称之为 SecondaryView ),该视图具有连接到您的操作的 @Binding 变量.这样,当LogInView()出现时,我们可以确保它肯定会渲染这个视图,然后我们可以通过改变@Binding动作来简单地修改这个视图的内容.

Instead of doing the 'if.. else if..' statement within the .sheet modifier, present a static view (I've called it SecondaryView ) that has a @Binding variable connected to your action. This way, when LogInView() appears, we can ensure that it will definitely render this view and then we can simply modify this view's content by changing the @Binding action.

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:让每个 Button 都有自己的 View,这样它就可以拥有自己的 .sheet 修饰符.

在 SwiftUI 中,每个视图仅限于 1 个 .sheet() 修饰符.但是,我们总是可以在视图中添加视图,然后每个子视图也可以使用它自己的 .sheet() 修饰符.所以简单的解决方案是让每个按钮都有自己的视图.我更喜欢这种方法,因为我们不再需要在视图之间传递@State/@Binding 变量.

In SwiftUI, we are limited to 1 .sheet() modifier per View. However, we can always add Views within Views and each subview is then allowed it's own .sheet() modifier as well. So the easy solution is to make each of your buttons their own view. I prefer this method because we no longer need to pass around the @State/@Binding variables between views.

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")
            })
    }
}

这篇关于多个底部工作表 - 内容不会加载 SwiftUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆