在没有NavigationButton的情况下通过API成功进行身份验证后,在SwftUI中选择了新视图 [英] Segue to a new view in SwftUI after a successful authentication from API without a NavigationButton

查看:49
本文介绍了在没有NavigationButton的情况下通过API成功进行身份验证后,在SwftUI中选择了新视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从API获得200 OK响应代码后,我试图选择一个全新的视图.响应代码成功发送回应用程序,并打印到控制台中并加载视图.当视图加载到前一个视图的顶部时除外. 我在说什么的照片.我无法使用导航按钮,因为您无法使用它们的瓶坯功能,并且我也不想在登录后在屏幕的左上方单击后退"按钮.这是我现在拥有的代码;

I am trying to segue to an entirely new view after I get a 200 OK response code from my API. The response code is successful sent back to the app and is printed into the console and the view is loaded. Except when the view loads in loads on top of the previous view. Photo of what I'm talking about. I can't use a navigation button because you can't have them preform functions and I don't want back button at the top left of the screen after a login. Here is the code I have now;

    @State var username: String = ""
    @State var password: String = ""
    @State var sayHello = false
    @State private var showingAreaView = false
    @State private var showingAlert = false
    @State private var alertTitle = ""
    @State private var alertMessage = ""

Button(action: {
      self.login()

      })//end of login function
               {
                       Image("StartNow 3").resizable()
                         .scaledToFit()
                        .padding()
                       }
                if showingAreaView == true {
                    AreaView()
                        .animation(.easeIn)
                }


//actual Login func

    func login(){
        let login = self.username
        let passwordstring = self.password
         guard let url = URL(string: "http://localhost:8000/account/auth/") else {return}

         let headers = [
             "Content-Type": "application/x-www-form-urlencoded",
             "cache-control": "no-cache",
             "Postman-Token": "89a81b3d-d5f3-4f82-8b7f-47edc39bb201"
         ]

         let postData = NSMutableData(data: "username=\(login)".data(using: String.Encoding.utf8)!)
         postData.append("&password=\(passwordstring)".data(using: String.Encoding.utf8)!)

         let request = NSMutableURLRequest(url: NSURL(string: "http://localhost:8000/account/auth/")! as URL,
             cachePolicy:.useProtocolCachePolicy, timeoutInterval: 10.0)
         request.httpMethod = "POST"
         request.allHTTPHeaderFields = headers
         request.httpBody = postData as Data

         let session = URLSession.shared
         let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in
             if let httpResponse = response as? HTTPURLResponse {
                 guard let data = data else {return}
                 print(data)
                 if httpResponse.statusCode == 200{
                     DispatchQueue.main.async {
                         //Segue to new view goes here
                         print(httpResponse.statusCode)
                        self.showingAreaView = true

                     }
                 }else{
             if httpResponse.statusCode == 400{
                     DispatchQueue.main.async {
                    self.alertTitle = "Oops"
                    self.alertMessage = "Username or Password Incorrect"
                    self.showingAlert = true
                         print(httpResponse.statusCode)

                         }
                     }else{
                         DispatchQueue.main.async {
                            self.alertTitle = "Well Damn"
                            self.alertMessage = "Ay chief we have no idea what just happened but it didn't work"
                            self.showingAlert = true

                         }
                     }
             }
                 do{

                     let JSONFromServer = try JSONSerialization.jsonObject(with: data, options: [])
                     let decoder = JSONDecoder()
                     decoder.keyDecodingStrategy = .convertFromSnakeCase
                     let tokenArray = try decoder.decode(token.self, from: data)
                     print(tokenArray.token)
                     UserDefaults.standard.set(tokenArray.token, forKey: "savedToken")
                     let savedToken = UserDefaults.standard.object(forKey: "savedToken")
                     print(savedToken)
                 }catch{
                     if httpResponse.statusCode == 400{
                    self.alertTitle = "Oops"
                    self.alertMessage = "Username or Password Incorrect"
                    self.showingAlert = true

                     }
                     print(error)
                     print(httpResponse.statusCode)
                 }
             } else if let error = error {
                self.alertTitle = "Well Damn"
                self.alertMessage = "Ay chief we have no idea what just happened but it didn't work"
                self.showingAlert = true
                 print(error)
             }
         })
         dataTask.resume()
    }


我已经厌倦了用Google搜索这个问题,但是没有任何运气.我所需要的只是一个基本视图,无需导航按钮.

I've tired to google this issue but haven't had any luck. All I need is a basic segue to a new view without the need of a NavigationButton.

感谢您的帮助!

推荐答案

假设您有两个基本视图(例如LoginViewMainView),则可以通过两种方式在它们之间进行转换.您需要的是:

Assuming you've got two basic views (e.g., a LoginView and a MainView), you can transition between them in a couple ways. What you'll need is:

  1. 确定要显示哪个状态的某种状态
  2. 某些包装视图将在#1更改时在两种布局之间转换
  3. 以某种方式在视图之间传递数据

在这个答案中,我将结合#1& #3在模型对象中,并显示#2的两个示例.您可以通过多种方法来实现这一目标,因此请尝试一下,看看哪种方法最适合您.

In this answer, I'll combine #1 & #3 in a model object, and show two examples for #2. There are lots of ways you could make this happen, so play around and see what works best for you.

请注意,有很多代码只是用来设置视图的样式,因此您可以看到正在发生的事情.我已经评论了关键部分.

Note that there is a lot of code just to style the views, so you can see what's going on. I've commented the critical bits.

图片(左侧为不透明度方法,右侧为偏移方法)

模型(满足#1和#3)

class LoginStateModel: ObservableObject {
    // changing this will change the main view
    @Published var loggedIn = false
    // will store the username typed on the LoginView
    @Published var username = ""

    func login() {
        // simulating successful API call
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            // when we log in, animate the result of setting loggedIn to true
            //   (i.e., animate showing MainView)
            withAnimation(.default) {
                self.loggedIn = true
            }
        }
    }
}

顶级视图(满足#2)

struct ContentView: View {
    @ObservedObject var model = LoginStateModel()

    var body: some View {
        ZStack {
            // just here for background
            Color(UIColor.cyan).opacity(0.3)
                .edgesIgnoringSafeArea(.all)

            // we show either LoginView or MainView depending on our model
            if model.loggedIn {
                MainView()
            } else {
                LoginView()
            }
        }
            // this passes the model down to descendant views
            .environmentObject(model)
    }
}

在视图层次结构中添加视图或从中删除视图的默认过渡是更改其不透明度.由于我们将对model.loggedIn的更改包装在withAnimation(.default)中,因此这种不透明性更改将缓慢发生(在实际设备上比下面的压缩GIF更好).

The default transition for adding and removing views from the view hierarchy is to change their opacity. Since we wrapped our changes to model.loggedIn in withAnimation(.default), this opacity change will happen slowly (its better on a real device than the compressed GIFs below).

或者,我们可以让视图使用偏移量在屏幕上切换,而不是使视图淡入/淡出.对于第二个示例,将上面的if/else块(包括if本身)替换为

Alternatively, instead of having the views fade in/out, we could have them move on/off screen using an offset. For the second example, replace the if/else block above (including the if itself) with

MainView()
    .offset(x: model.loggedIn ? 0 : UIScreen.main.bounds.width, y: 0)
LoginView()
    .offset(x: model.loggedIn ? -UIScreen.main.bounds.width : 0, y: 0)

登录视图

struct LoginView: View {
    @EnvironmentObject var model: LoginStateModel

    @State private var usernameString = ""
    @State private var passwordString = ""

    var body: some View {
        VStack(spacing: 15) {
            HStack {
                Text("Username")
                Spacer()
                TextField("Username", text: $usernameString)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
            }
            HStack {
                Text("Password")
                Spacer()
                SecureField("Password", text: $passwordString)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
            }
            Button(action: {
                // save the entered username, and try to log in
                self.model.username = self.usernameString
                self.model.login()
            }, label: {
                Text("Login")
                    .font(.title)
                    .inExpandingRectangle(Color.blue.opacity(0.6))
            })
                .buttonStyle(PlainButtonStyle())
        }
        .padding()
        .inExpandingRectangle(Color.gray)
        .frame(width: 300, height: 200)
    }
}

请注意,在真实的功能性登录表单中,您需要进行一些基本的输入操作,并禁用/限制登录按钮的速率,以便在有人向该按钮发送垃圾邮件时不会收到十亿个服务器请求.

Note that in a real functional login form, you'd want to do some basic input sanitation and disable/rate limit the login button so you don't get a billion server requests if someone spams the button.

有关灵感的信息,请参见:
引入合并(WWDC会议)
实践结合(WWDC会议)
使用组合(UIKit示例,但显示了如何限制网络请求)

For inspiration, see:
Introducing Combine (WWDC Session)
Combine in Practice (WWDC Session)
Using Combine (UIKit example, but shows how to throttle network requests)

主视图

struct MainView: View {
    @EnvironmentObject var model: LoginStateModel

    var body: some View {
        VStack(spacing: 15) {
            ZStack {
                Text("Hello \(model.username)!")
                    .font(.title)
                    .inExpandingRectangle(Color.blue.opacity(0.6))
                    .frame(height: 60)

                HStack {
                    Spacer()
                    Button(action: {
                        // when we log out, animate the result of setting loggedIn to false
                        //   (i.e., animate showing LoginView)
                        withAnimation(.default) {
                            self.model.loggedIn = false
                        }
                    }, label: {
                        Text("Logout")
                            .inFittedRectangle(Color.green.opacity(0.6))
                    })
                        .buttonStyle(PlainButtonStyle())
                        .padding()
                }
            }

            Text("Content")
                .inExpandingRectangle(.gray)
        }
        .padding()
    }
}

一些便捷扩展

extension View {
    func inExpandingRectangle(_ color: Color) -> some View {
        ZStack {
            RoundedRectangle(cornerRadius: 15)
                .fill(color)
            self
        }
    }

    func inFittedRectangle(_ color: Color) -> some View {
        self
            .padding(5)
            .background(RoundedRectangle(cornerRadius: 15)
                .fill(color))
    }
}

这篇关于在没有NavigationButton的情况下通过API成功进行身份验证后,在SwftUI中选择了新视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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