Skip to content

Kotlin Codes

  • Home
  • Flutter
  • Kotlin
  • SwiftUI
  • About Me
  • Home
    • Blog
    • Privacy Policy
  • Flutter
    • Widgets In Flutter
      • Cupertino Widgets
      • iOS Styling Flutter
    • Database & Storage
    • State Management in Flutter
    • Performance Optimization
    • Networking & APIs
    • Testing & Debugging
  • Kotlin
    • Kotlin XML Development(Traditional View-based UI)
      • Introduction to XML UI Development
      • State Management and Architecture
      • Advanced Topics
      • Firebase and Cloud Integration
      • UI Components and Customization
      • Media and Visual Enhancements
      • Navigation and Data Handling
      • UI Performance Optimization
      • Networking and Data Management
    • Jetpack Compose
      • UI Elements
      • Kotlin Multiplatform
      • Accessibility
      • Animation
      • Core Concepts
      • Custom Drawing
      • Interoperability
      • Layouts
      • State Management
      • Modifiers
      • Navigation
      • Testing
      • Theming
      • Performance
    • Kotin-CodeChallenge
  • SwiftUI
  • About Me

Building a Login Screen with SwiftUI

March 1, 2025May 15, 2025 Sayandh

Creating a login screen is a fundamental task in mobile app development. SwiftUI, Apple’s modern UI framework, makes this process straightforward and enjoyable. In this comprehensive guide, we’ll walk through building a stylish and functional login screen using SwiftUI. We’ll cover UI design, state management, data validation, and secure password handling, providing code snippets and best practices along the way.

What is SwiftUI?

SwiftUI is a declarative UI framework developed by Apple for building user interfaces across all Apple platforms, including iOS, macOS, watchOS, and tvOS. Its key benefits include:

  • Declarative Syntax: UI is described using code that represents the desired state, rather than step-by-step instructions.
  • Live Preview: See real-time updates in the Xcode canvas as you code.
  • Cross-Platform: Share code across different Apple platforms.
  • Data Binding: Seamless integration with data and state management.

Why Use SwiftUI for Login Screens?

  • Modern Approach: Embraces contemporary UI development practices.
  • Simplified Code: Reduces boilerplate code compared to UIKit.
  • Easy to Understand: Clear and concise syntax makes UI code more readable.
  • Improved Maintainability: Promotes better separation of concerns.

Setting Up the Project

Before we start, make sure you have Xcode installed. Create a new Xcode project, select the “App” template, choose SwiftUI for the interface, and Swift as the language.

Designing the UI

Our login screen will consist of the following elements:

  • App Logo
  • Email Text Field
  • Password Text Field
  • Login Button
  • Optional: Forgot Password Link, Sign Up Link

Here’s the code to set up the basic UI structure:


import SwiftUI

struct LoginView: View {
    @State private var email = ""
    @State private var password = ""

    var body: some View {
        NavigationView {
            VStack {
                // App Logo
                Image(systemName: "lock.shield.fill")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 120, height: 120)
                    .padding(.bottom, 30)

                // Email Field
                TextField("Email", text: $email)
                    .padding()
                    .background(Color(.secondarySystemBackground))
                    .cornerRadius(10)
                    .padding(.bottom, 20)

                // Password Field
                SecureField("Password", text: $password)
                    .padding()
                    .background(Color(.secondarySystemBackground))
                    .cornerRadius(10)
                    .padding(.bottom, 30)

                // Login Button
                Button(action: {
                    // Perform login action
                    print("Login tapped with email: (email), password: (password)")
                }) {
                    Text("Login")
                        .foregroundColor(.white)
                        .frame(maxWidth: .infinity)
                        .padding()
                        .background(Color.blue)
                        .cornerRadius(10)
                }

                Spacer() // Push content to top
            }
            .padding()
            .navigationTitle("Login")
        }
    }
}

struct LoginView_Previews: PreviewProvider {
    static var previews: some View {
        LoginView()
    }
}

In this code:

  • @State private var email and @State private var password: Declare state variables to hold the email and password inputs.
  • NavigationView: Wraps the content to provide a navigation bar.
  • VStack: Vertically stacks the UI elements.
  • Image: Displays an image for the app logo.
  • TextField: Allows users to enter their email.
  • SecureField: Allows users to enter their password, hiding the input.
  • Button: Triggers the login action.
  • Spacer(): Pushes the content to the top of the screen.

Adding Styles and Polish

Let’s enhance the UI with custom styling and theming for a more appealing look.


import SwiftUI

struct LoginView: View {
    @State private var email = ""
    @State private var password = ""
    @State private var isPasswordVisible = false // Added password visibility state

    var body: some View {
        NavigationView {
            ZStack { // Added ZStack for background color
                Color(.systemBackground).edgesIgnoringSafeArea(.all) // Setting background color
                
                VStack {
                    // App Logo
                    Image(systemName: "lock.shield.fill")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 120, height: 120)
                        .foregroundColor(.blue) // Adjusted color
                        .padding(.bottom, 30)

                    // Email Field
                    TextField("Email", text: $email)
                        .padding()
                        .background(Color(.secondarySystemBackground))
                        .cornerRadius(10)
                        .padding(.bottom, 20)
                        .keyboardType(.emailAddress) // Keyboard type for email
                        .autocapitalization(.none)    // Disable auto-capitalization
                    
                    // Password Field with Password Visibility Toggle
                    HStack {
                        if isPasswordVisible {
                            TextField("Password", text: $password)
                        } else {
                            SecureField("Password", text: $password)
                        }
                        
                        Button(action: {
                            isPasswordVisible.toggle() // Toggle password visibility
                        }) {
                            Image(systemName: isPasswordVisible ? "eye.slash" : "eye") // Eye icon
                                .foregroundColor(.gray)
                        }
                    }
                    .padding()
                    .background(Color(.secondarySystemBackground))
                    .cornerRadius(10)
                    .padding(.bottom, 30)


                    // Login Button
                    Button(action: {
                        // Perform login action
                        print("Login tapped with email: (email), password: (password)")
                    }) {
                        Text("Login")
                            .foregroundColor(.white)
                            .font(.headline)  // Headline font for button
                            .frame(maxWidth: .infinity)
                            .padding()
                            .background(Color.blue)
                            .cornerRadius(10)
                    }

                    // Forgot Password Link
                    Button(action: {
                        // Navigate to forgot password view
                        print("Forgot password tapped")
                    }) {
                        Text("Forgot Password?")
                            .foregroundColor(.gray)
                            .padding(.top, 10)
                    }
                    
                    Spacer() // Push content to top
                    
                    // Sign Up Link
                    HStack {
                        Text("Don't have an account?")
                            .foregroundColor(.gray)
                        
                        Button(action: {
                            // Navigate to sign-up view
                            print("Sign up tapped")
                        }) {
                            Text("Sign Up")
                                .foregroundColor(.blue)
                        }
                    }
                    .padding(.bottom, 20) // Add padding at the bottom

                }
                .padding()
                .navigationTitle("Login")
                .alert(isPresented: .constant(false)) {  // Sample alert
                    Alert(title: Text("Error"), message: Text("Invalid Credentials."), dismissButton: .default(Text("OK")))
                }
            }
        }
    }
}

struct LoginView_Previews: PreviewProvider {
    static var previews: some View {
        LoginView()
    }
}

Key enhancements:

  • Background Color: Added a ZStack to set the background color.
  • Color Adjustments: Applied custom colors to the logo and text elements.
  • Font Styling: Updated the font for the login button.
  • Keyboard Type and Autocapitalization: Set appropriate keyboard types and disabled auto-capitalization for the email field.
  • Password visibility: The password can now be toggled from secure to visible for convenience and accessibility for some users.
  • Forgot Password and Sign Up Links: Added optional links for improved user experience.
  • Alert View: Added Alert Message to alert the users upon login failures.

Data Validation

Validating user inputs is crucial for security and user experience. Add validation to the email and password fields.


import SwiftUI

struct LoginView: View {
    @State private var email = ""
    @State private var password = ""
    @State private var isPasswordVisible = false
    @State private var showAlert = false       // Alert visibility state
    @State private var alertMessage = ""        // Alert message

    // Email validation function
    func isValidEmail(_ email: String) -> Bool {
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,64}"
        let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailRegex)
        return emailPredicate.evaluate(with: email)
    }

    var body: some View {
        NavigationView {
            ZStack {
                Color(.systemBackground).edgesIgnoringSafeArea(.all)

                VStack {
                    Image(systemName: "lock.shield.fill")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 120, height: 120)
                        .foregroundColor(.blue)
                        .padding(.bottom, 30)

                    TextField("Email", text: $email)
                        .padding()
                        .background(Color(.secondarySystemBackground))
                        .cornerRadius(10)
                        .padding(.bottom, 20)
                        .keyboardType(.emailAddress)
                        .autocapitalization(.none)
                        .disableAutocorrection(true)  // Disable autocorrection

                    HStack {
                        if isPasswordVisible {
                            TextField("Password", text: $password)
                        } else {
                            SecureField("Password", text: $password)
                        }

                        Button(action: {
                            isPasswordVisible.toggle()
                        }) {
                            Image(systemName: isPasswordVisible ? "eye.slash" : "eye")
                                .foregroundColor(.gray)
                        }
                    }
                    .padding()
                    .background(Color(.secondarySystemBackground))
                    .cornerRadius(10)
                    .padding(.bottom, 30)

                    Button(action: {
                        // Validation logic
                        if email.isEmpty || password.isEmpty {
                            alertMessage = "Please fill in all fields."
                            showAlert = true
                        } else if !isValidEmail(email) {
                            alertMessage = "Please enter a valid email address."
                            showAlert = true
                        } else if password.count < 6 {
                            alertMessage = "Password must be at least 6 characters."
                            showAlert = true
                        } else {
                            // Perform login action if validation passes
                            print("Login tapped with valid credentials.")
                        }
                    }) {
                        Text("Login")
                            .foregroundColor(.white)
                            .font(.headline)
                            .frame(maxWidth: .infinity)
                            .padding()
                            .background(Color.blue)
                            .cornerRadius(10)
                    }

                    Button(action: {
                        print("Forgot password tapped")
                    }) {
                        Text("Forgot Password?")
                            .foregroundColor(.gray)
                            .padding(.top, 10)
                    }

                    Spacer()

                    HStack {
                        Text("Don't have an account?")
                            .foregroundColor(.gray)

                        Button(action: {
                            print("Sign up tapped")
                        }) {
                            Text("Sign Up")
                                .foregroundColor(.blue)
                        }
                    }
                    .padding(.bottom, 20)
                }
                .padding()
                .navigationTitle("Login")
                .alert(isPresented: $showAlert) {
                    Alert(title: Text("Error"), message: Text(alertMessage), dismissButton: .default(Text("OK")))
                }
            }
        }
    }
}

struct LoginView_Previews: PreviewProvider {
    static var previews: some View {
        LoginView()
    }
}

Additions to Data Validation Code

  • disableAutocorrection(.true) will avoid iOS to attempt correct and/or suggest on email which might not what users expects.
  • Email Validation checks by isValidEmail() makes sure to email format validation.
  • Length and presence check ensures there’s no credential can proceed that’s blank, email not valid, and with less secure password, the process doesn’t continues.

Enhancements for data validation

  • Show the user errors immediately using conditional view modifiers based on the length of fields.
  • The user must enter credentials meeting criteria (Email in good pattern), and the password meets minimum length policies
  • showAlert – is set for a variety of reasons and alertMessage, to indicate validation failures.

State Management

For complex apps, consider using a state management solution like @ObservedObject, @EnvironmentObject, or Redux-like architecture.

Example using @ObservedObject:


import SwiftUI
import Combine

class AuthenticationViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    @Published var isLoggedIn = false

    func login() {
        // Perform login logic
        // On success, set isLoggedIn to true
        isLoggedIn = true
    }
}

struct ContentView: View {
    @ObservedObject var authViewModel = AuthenticationViewModel()

    var body: some View {
        if authViewModel.isLoggedIn {
            Text("Welcome!")
        } else {
            LoginView(authViewModel: authViewModel)
        }
    }
}

struct LoginView: View {
    @ObservedObject var authViewModel: AuthenticationViewModel

    var body: some View {
        VStack {
            TextField("Email", text: $authViewModel.email)
            SecureField("Password", text: $authViewModel.password)

            Button(action: {
                authViewModel.login()
            }) {
                Text("Login")
            }
        }
    }
}

Conclusion

Building a login screen with SwiftUI is efficient and allows for easy customization and styling. This guide has provided you with the foundational knowledge to create a modern and functional login interface, covering UI design, state management, data validation, and security practices. Remember to adopt these techniques to enhance user experience and security in your apps.

Beyond This Article: Your Next Discovery Awaits

SwiftUI Widgets: Adding Home Screen Widgets to Your App
Understanding Different State Management Approaches in Flutter
Using SwiftUI’s Grids to Create Photo Galleries
Creating a Todo List App with SwiftUI
Building a Restaurant Menu App in SwiftUI
Navigation in SwiftUI: NavigationStack, NavigationLink, and NavigationDestination
Tagged with Apple UI Framework, Data Validation SwiftUI, iOS app development, iOS Login Tutorial, Login Authentication, Login Screen Design, SwiftUI Login Screen, SwiftUI Security, SwiftUI State Management, SwiftUI Tutorial
  • SwiftUI

Post navigation

Previous Post

SwiftUI State Management: @State, @Binding, @ObservedObject, and @EnvironmentObject

Next Post

Adding Barcode and QR Code Scanning in Flutter

Recents

  • Working with Firestore, Firebase’s Scalable NoSQL Cloud Database, for Storing and Retrieving Application Data in Flutter
  • Performing Integration Testing to Validate the Interaction Between Different Parts of Your Flutter Application
  • Using Packages Like upgrader to Facilitate the In-App Update Process in Flutter
  • Implementing In-App Updates to Allow Users to Update Your App Without Leaving It in Flutter
  • Analyzing Analytics Data to Gain Insights into User Engagement and Identify Areas for Improvement in Flutter
  • Dart
  • Flutter
    • Advanced Concepts
    • Animations & UI Enhancements
    • Data Handling (JSON, REST APIs, Databases)
    • Database & Storage
    • Input Widgets
    • iOS Styling Flutter
    • Layout Widgets
    • Navigation and Routing
    • Networking & APIs
    • Performance Optimization
    • Platform Integration (Native Features)
    • State Management (Provider, BLoC, Riverpod)
    • State Management in Flutter
    • Testing (Unit, Widget, Integration)
    • Testing & Debugging
    • UI Basics
    • Widgets In Flutter
      • Cupertino Widgets
  • Kotlin
    • Jetpack Compose
      • Accessibility
      • Animation
      • Core Concepts
      • Custom Drawing
      • Interoperability
      • Kotlin Multiplatform
      • Layouts
      • Modifiers
      • Navigation
      • Performance
      • State Management
      • Testing
      • Theming
      • UI Elements
    • Kotin-CodeChallenge
    • Kotlin XML Development(Traditional View-based UI)
      • Accessibility
      • Advanced Topics
      • Advanced Topics & Custom Views
      • Animation
      • Data Binding
      • Drawables
      • Firebase and Cloud Integration
      • Introduction to XML UI Development
      • Kotlin Integration & Patterns
      • Layouts
      • Media and Visual Enhancements
      • Navigation and Data Handling
      • Networking and Data Management
      • RecyclerView
      • State Management and Architecture
      • Styles & Themes
      • UI Components and Customization
      • UI Performance Optimization
      • View Binding
      • Views
      • XML Techniques
  • SwiftUI

© KotlinCodes. Explore the latest Kotlin tutorials, Flutter guides, and Dart programming tips. | Learn Kotlin | Flutter Development | Dart Programming | Flutter Widgets