SwiftUI is a relatively new technology that offers an exciting way to build user interfaces for iOS apps on the Apple platform. In the following series of tutorials we will be showing you how to create a Login page in SwiftUI when you build a chat app using QuickBlox iOS SDK.
In the following tutorial you will learn how create text fields and buttons as part of your iOS app UI using SwiftUI. We will show you how to build a login screen user interface similar to the one shown in the image below:
This screen consists of the following 4 elements:
We can also see that the NavigationView is used with the title “Enter to chat.”
First you need to login to your QuickBlox account and connect to the QuickBlox iOS SDK so that you can request data from the server.
You can learn how to create a project and connect the QuickBlox SDK in an earlier blog, How to create an application in your QuickBlox account.
We recommend downloading the current project from this GitHub repository, or you can use own resources for the user interface.
If you choose not to download from the repository and instead build from scratch, we recommend that you still name it QuickbloxSwiftUIChat, as we will be referring to this specific file name in the instructions below.
The Login screen is the gateway to most apps. For the app you’re creating, users must enter their Login and Password on this vital first screen in order to access the application and log into the QuickBlox system.
Here’s how to start building do this:
First, create a new file and name it “Login Screen.”
Then, tell your application to open the “LoginScreen” when logging in.
Next, go to the LoginScreen file and in the body add your info text: Text(“Enter your login and display name”) with some settings and wrap it in a VStack. To do this, create a new InfoText structure:
struct InfoText: View { var body: some View { Text("Enter your login and password") .font(.system(size: 16, weight: .light)) .foregroundColor(.primary) } }
And paste it into the LoginScreen:
struct LoginScreen: View { var body: some View { VStack(spacing: 28) { InfoText().padding(.top, 44) } .padding() } }
Before you go any further, you need to wrap your VStack in a NavigationView and customize its appearance.
Create a new View+Extension.swift file and make an extension for the View structure to customize the NavigationBar:
import SwiftUI extension View { func setupNavigationBarAppearance(titleColor: UIColor, barColor: UIColor) { let appearance = UINavigationBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundColor = barColor appearance.titleTextAttributes = [.foregroundColor: titleColor] UINavigationBar.appearance().standardAppearance = appearance UINavigationBar.appearance().compactAppearance = appearance UINavigationBar.appearance().scrollEdgeAppearance = appearance } }
Place this file in the Utils folder.
Then you will set up the NavigationView.
import SwiftUI struct LoginScreen: View { init() { setupNavigationBarAppearance(titleColor: UIColor.white, barColor: UIColor(.blue)) } var body: some View { NavigationView { VStack(spacing: 28) { InfoText().padding(.top, 44) Spacer() } .navigationBarTitle("Enter to chat", displayMode: .inline) } } }
Further, according to the design, you should have two data entry fields so that the user can enter their login and password. To do this, you will create two variables with the @State modifier in order to keep track of the entered data:
@State private var login: String = "" @State private var password: String = “"
Use a TextField to enter the Login and a SecureField to enter the Password. Now add them to LoginScreen with settings to match the design:
struct LoginScreen: View { @State private var login: String = "" @State private var password: String = "" init() { setupNavigationBarAppearance(titleColor: UIColor.white, barColor: UIColor(.blue)) } var body: some View { NavigationView { VStack(spacing: 28) { InfoText().padding(.top, 44) VStack(alignment: .leading, spacing: 11) { Text("Login") .font(.system(size: 13, weight: .light)) .foregroundColor(.secondary) .frame(height: 15, alignment: .leading) TextField("", text: $login) .font(.system(size: 17, weight: .thin)) .foregroundColor(.primary) .frame(height: 44) .padding(.horizontal, 12) .background(Color.white) .cornerRadius(4.0) } VStack(alignment: .leading, spacing: 11) { Text("Password") .font(.system(size: 13, weight: .light)) .foregroundColor(.secondary) .frame(height: 15, alignment: .leading) SecureField("", text: $password) .font(.system(size: 17, weight: .thin)) .foregroundColor(.primary) .frame(height: 44) .padding(.horizontal, 12) .background(Color.white) .cornerRadius(4.0) } Spacer() } .padding() .background(.secondary.opacity(0.1)) .navigationBarTitle("Enter to chat", displayMode: .inline) } } }
This is how your screen should currently look:
Move the repetitive Text(“Login”) and Text(“Password”) code into a new TextFieldName structure:
struct TextFieldName: View { let name: String var body: some View { Text(name) .font(.system(size: 13, weight: .light)) .foregroundColor(.secondary) .frame(height: 15, alignment: .leading) } } Now your code looks like this: struct LoginScreen: View { @State private var login: String = "" @State private var password: String = "" init() { setupNavigationBarAppearance(titleColor: UIColor.white, barColor: UIColor(.blue)) } var body: some View { NavigationView { VStack(spacing: 28) { InfoText().padding(.top, 44) VStack(alignment: .leading, spacing: 11) { TextFieldName(name: "Login") TextField("", text: $login) .font(.system(size: 17, weight: .thin)) .foregroundColor(.primary) .frame(height: 44) .padding(.horizontal, 12) .background(Color.white) .cornerRadius(4.0) } VStack(alignment: .leading, spacing: 11) { TextFieldName(name: "Password") SecureField("", text: $password) .font(.system(size: 17, weight: .thin)) .foregroundColor(.primary) .frame(height: 44) .padding(.horizontal, 12) .background(Color.white) .cornerRadius(4.0) } Spacer() } .padding() .background(.secondary.opacity(0.1)) .navigationBarTitle("Enter to chat", displayMode: .inline) } } }
Now you just need to add the “Login” button:
struct LoginScreen: View { @State private var login: String = "" @State private var password: String = "" init() { setupNavigationBarAppearance(titleColor: UIColor.white, barColor: UIColor(.blue)) } var body: some View { NavigationView { VStack(spacing: 28) { InfoText().padding(.top, 44) VStack(alignment: .leading, spacing: 11) { TextFieldName(name: "Login") TextField("", text: $login) .font(.system(size: 17, weight: .thin)) .foregroundColor(.primary) .frame(height: 44) .padding(.horizontal, 12) .background(Color.white) .cornerRadius(4.0) } VStack(alignment: .leading, spacing: 11) { TextFieldName(name: "Password") SecureField("", text: $password) .font(.system(size: 17, weight: .thin)) .foregroundColor(.primary) .frame(height: 44) .padding(.horizontal, 12) .background(Color.white) .cornerRadius(4.0) } Button { debugPrint("Login Button Tapped!") } label: { Text("Login") .foregroundColor(.white) .font(.system(size: 18)) .frame(width: 215, height: 44, alignment: .center) } .background(.secondary) .cornerRadius(4) .padding(.top, 36) Spacer() } .padding() .background(.secondary.opacity(0.1)) .navigationBarTitle("Enter to chat", displayMode: .inline) } } }
This is how your screen should now look:
You have now created a basic login screen. In the next part, we will show you how to validate entered data, animate the UI, and continue to improve your code.