
In the realm of iOS development, using Swift UI for constructing interactive and user-centric interfaces is indispensable. This tutorial is designed to delve into the practical implementation of Lists within Swift UI, an essential component for the structured presentation of data.
We will explore the procedures for dynamically adding and removing entries in a list, focusing on names. Moreover, to ensure data integrity and enhance user input quality, we will integrate regular expression (regex) based validation for the text field, allowing only valid names to be added to the list.
Embark on this technical journey to refine your Swift UI development skills by creating a dynamic list with validated input.
Begin by initiating a new project in Xcode, selecting the “App” template as your starting point. Once done, navigate to the ContentView.swift file to apply the necessary updates as outlined below.
Kick-off this practical exercise by creating a new project in Xcode. Choose the App template for the foundation of your work.
After setting up your project, proceed to the ContentView.swift file, where I will guide you through the updates and modifications required to bring our dynamic list to life.
import SwiftUI
// Defines the main view of the app, managing a list of names with validation and deletion capabilities.
struct ContentView: View {
// State variables to dynamically update the UI based on user interaction.
@State private var names = ["Alice", "Bob", "Charlie", "David"] // The list of names displayed in the UI.
@State private var newName: String = "" // The current input from the user for a new name.
@State private var showError = false // Controls the visibility of an error message for invalid names.
// Key Point 1: Name Validation
let namePredicate = NSPredicate(format: "SELF MATCHES %@", "^[a-zA-ZÀ-ÿ-.' ]+$")
// Builds the UI elements displayed to the user.
var body: some View {
VStack {
HStack {
// User input field for adding new names. Utilizes two-way binding to update 'newName' in real-time.
TextField("Enter name", text: $newName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
// Button to trigger adding the new name to the list. Disabled if the name does not pass validation.
Button("Add") { addName() }
.disabled(!isValidName(newName))
.padding()
}
// Conditionally displayed error message for invalid name inputs.
if showError {
Text("Invalid name. Please use letters only.")
.foregroundColor(.red)
.padding(.bottom)
}
// Key Point 2: Dynamic List with Deletion
List {
ForEach(names, id: \\.self) { name in
Text(name)
}
.onDelete(perform: delete)
}
}
}
// Attempts to add the new name to the list if it passes validation
func addName() {
if isValidName(newName) {
names.append(newName)
newName = "" // Resets the input field for a new name
showError = false // Hides the error message if previously shown
} else {
showError = true // Shows an error message if the name is invalid
}
}
// Removes a name from the list based on user selection
func delete(at offsets: IndexSet) {
names.remove(atOffsets: offsets)
}
// Checks if the provided name string matches the defined regular expression pattern
func isValidName(_ name: String) -> Bool {
// Uses the pre-initialized NSPredicate for efficient validation
return namePredicate.evaluate(with: name)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
isValidName() function leverages an NSPredicate defined by the regex pattern "^[a-zA-ZÀ-ÿ-.' ]+$". This pattern allows names containing letters (including accented characters), hyphens, apostrophes, and spaces, thus accommodating a wide range of international names.NSPredicate just once and reapplying it for each validation. This approach eliminates the redundancy of recreating the predicate with every new input, streamlining the validation process.List view is a powerful tool for displaying a collection of items in a structured manner.id: \\.self. This identification method allows SwiftUI to render updates to the list efficiently, such as additions or deletions..onDelete(perform: delete) modifier attached to the ForEach loop within our List is particularly noteworthy. It enables swipe-to-delete functionality, invoking the delete(at:) function when a user swipes on a list item.delete function then removes the corresponding entry from the names array based on the user's selection, dynamically updating the UI to reflect this change. This feature makes our list interactive and empowers users to manage their entries easily.