December 23, 2024
•
Welcome to Part 3 of our SwiftUI series! After understanding the basics in Part 1, it’s time to focus on building beautiful, dynamic, and interactive user interfaces with SwiftUI. This part is all about taking your UI skills to the next level by exploring essential components and techniques for crafting seamless app experiences.
So, let’s start your Swift journey and understand each topic in detail!
Form Elements
We use TextField, SecureField, and Picker to create forms in SwiftUI. Forms handle user inputs and make them interactive. Here we will see:
- Using TextField, SecureField, and Picker in forms.
- Styling forms and managing inputs.
Let’s understand in detail!
Creating Forms with TextField
, SecureField
, and Pickers
import SwiftUI
struct ContentView: View {
@State private var username: String = ""
@State private var password: String = ""
var body: some View {
Form {
Section(header: Text("Login Details")) {
TextField("Enter your username", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
SecureField("Enter your password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
Button(action: {
print("Username: \(username), Password: \(password)")
}) {
Text("Submit")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
.padding()
}
}
- TextField: To take text input from the user.
- SecureField: For password or sensitive input.
- @state: Dynamically manages the input values.
Picker in a Form
struct ContentView: View {
@State private var selectedOption = "Swift"
let options = ["Swift", "Kotlin", "Java", "Python"]
var body: some View {
Form {
Section(header: Text("Choose your favorite language")) {
Picker("Select an option", selection: $selectedOption) {
ForEach(options, id: \.self) { option in
Text(option)
}
}
.pickerStyle(MenuPickerStyle()) // Dropdown-style picker
}
Text("You selected: \(selectedOption)")
.font(.headline)
}
}
}
- Picker: Used to select options.
- MenuPickerStyle: Displays a dropdown-style picker.
- ForEach: Dynamically iterates the options.
Styling Forms and Managing Input
In SwiftUI, you can easily style form elements using modifiers.
struct ContentView: View {
@State private var email = ""
var body: some View {
Form {
Section(header: Text("User Info").font(.headline)) {
TextField("Enter your email", text: $email)
.padding()
.background(Color.gray.opacity(0.2))
.cornerRadius(8)
.keyboardType(.emailAddress) // Keyboard type set karein
.autocapitalization(.none) // Automatic capitalization disable karein
}
Button(action: {
print("Email entered: \(email)")
}) {
Text("Submit")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
.foregroundColor(.white)
.cornerRadius(10)
}
}
.padding()
}
}
- keyboardType: Sets the keyboard type (e.g., email, number, etc.).
- autocapitalization: Controls automatic capitalization.
- Styling modifiers like padding(), background(), and cornerRadius() make the form visually appealing.
Styling UI with Shapes and Colors in SwiftUI
SwiftUI uses Shapes and Colors to make the UI visually attractive and interactive. You can create custom shapes using Circle, Rectangle, and Path, and style them by adding gradients, shadows, and effects.
Let’s understand how it works!
Adding Custom Shapes Using Circle, Rectangle, and Path
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
Circle()
.fill(Color.blue)
.frame(width: 100, height: 100)
Rectangle()
.fill(Color.green)
.frame(width: 120, height: 60)
RoundedRectangle(cornerRadius: 20)
.fill(Color.purple)
.frame(width: 150, height: 80)
}
}
}
- Circle(): Creates a circular shape.
- Rectangle(): Creates a rectangular shape.
- RoundedRectangle: Creates a rectangle with rounded corners.
- .fill(Color): Used to fill the shape with a color.
Applying Gradients, Shadows, and Other Effects
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
Circle()
.fill(LinearGradient(gradient: Gradient(colors: [Color.red, Color.blue]), startPoint: .top, endPoint: .bottom))
.frame(width: 100, height: 100)
Rectangle()
.fill(RadialGradient(gradient: Gradient(colors: [Color.green, Color.yellow]), center: .center, startRadius: 10, endRadius: 60))
.frame(width: 120, height: 60)
RoundedRectangle(cornerRadius: 20)
.fill(AngularGradient(gradient: Gradient(colors: [Color.purple, Color.orange, Color.purple]), center: .center))
.frame(width: 150, height: 80)
}
}
}
- LinearGradient: Creates a top-to-bottom or left-to-right gradient.
- RadialGradient: Creates a circular gradient.
- AngularGradient: Creates a rotational gradient.
Combining Shapes and Effects
struct ContentView: View {
var body: some View {
ZStack {
Circle()
.fill(LinearGradient(gradient: Gradient(colors: [Color.pink, Color.purple]), startPoint: .top, endPoint: .bottom))
.frame(width: 200, height: 200)
.shadow(color: Color.purple.opacity(0.5), radius: 10, x: 0, y: 10)
Text("SwiftUI")
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(.white)
}
}
}
- ZStack: Arranges shapes and elements layer by layer.
- A combination of gradients, shadows, and text styling creates a visually appealing design.
- Custom UI can be created using shapes such as Circle, Rectangle, and Path.
- Gradients and Shadows can make the UI visually stunning.
- Shapes and colors can be further enhanced using modifiers.
Handling Navigation and Deep Link
Navigation in SwiftUI has become very simple. We can link similar pages using NavigationView and NavigationLink.
Basic Navigation using NavigationView
and NavigationLink
:
NavigationView is a container view that handles the navigation stack. We can link one view to another view using NavigationLink.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Text("Welcome to SwiftUI Navigation!")
.font(.largeTitle)
.padding()
NavigationLink(destination: DetailView()) {
Text("Go to Details")
.font(.title)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
.navigationTitle("Home") // Title of this view
}
}
}
struct DetailView: View {
var body: some View {
VStack {
Text("This is the Detail View!")
.font(.title)
Spacer()
}
.navigationTitle("Details") // Title of the next view
}
}
- NavigationView: This gives our content a navigable context.
- NavigationLink: This triggers an action so that we navigate to a new view.
struct ContentView: View {
var body: some View {
VStack(spacing: 30) {
Text("User Profile")
.font(.largeTitle)
.fontWeight(.bold)
- VStack: The main layout is vertical.
- HStack: Profile picture and details are stacked horizontally.
- ZStack: Text is placed on top of a rounded rectangle for button design.
Aligning and Customizing Stacks
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Text("Welcome to SwiftUI Navigation!")
.font(.largeTitle)
.padding()
}
.navigationTitle("Home")
.navigationBarItems(trailing:
Button(action: {
print("Settings tapped")
}) {
Image(systemName: "gearshape")
}
)
}
}
}
navigationBarItems: Is se hum navigation bar pe buttons ya actions add kar sakte hain, jaise ki gear icon.
Advanced Navigation: Using NavigationStack
:
SwiftUI 4 introduces a new approach called NavigationStack. It is more flexible than the previous NavigationView and provides more predictable behavior.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationStack {
VStack {
Text("Welcome to SwiftUI with NavigationStack!")
.font(.largeTitle)
.padding()
NavigationLink("Go to Settings", value: "SettingsView")
}
.navigationDestination(for: String.self) { value in
Text("This is \(value)!")
}
.navigationTitle("Home")
}
}
}
- NavigationStack: This is a newer approach which makes view navigation a little more structured.
- NavigationDestination: This method handles our destination view dynamically, based on the value.
Passing Data Between Views:
If we need to pass data from one view to another view, we can easily pass the data through the destination with NavigationLink.
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink("Go to Details", destination: DetailView(message: "Hello from Home"))
.padding()
}
}
}
struct DetailView: View {
var message: String
var body: some View {
VStack {
Text(message)
.font(.title)
.padding()
Spacer()
}
.navigationTitle("Details")
}
}
NavigationLink(destination:): Here we are passing the data to DestinationView using the implementation.
Customizing Navigation Bar with Large Titles and Back Button:
We can further customize the navigation bar in SwiftUI. We can set navigation bar right side up display mode and custom back buttons.
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink("Go to Settings", destination: SettingsView())
.padding()
}
}
}
struct SettingsView: View {
var body: some View {
VStack {
Text("Settings Screen")
.font(.title)
.padding()
}
.navigationTitle("Settings")
.navigationBarTitleDisplayMode(.large) // Large title
.navigationBarBackButtonHidden(true) // Hide default back button
.navigationBarItems(leading: Button(action: {
print("Custom Back Button Tapped")
}) {
Image(systemName: "arrow.left")
})
}
}
navigationBarTitleDisplayMode(.large)
:This modifier is used to display a large title on the navigation bar.navigationBarBackButtonHidden
: This modifier allows you to hide the default back button from the navigation bar.navigationBarItems(leading)
:This modifier allows you to add custom items (like a back button) to the navigation bar. Theleading
parameter places the item on the left side of the navigation bar.
Deep Linking in SwiftUI
Deep linking means opening a specific screen directly from an external source (such as a URL scheme or universal link).
To handle deep linking in Swifty, we use the onOpenURL modifier, which provides the capability to handle any URL.
import SwiftUI
@main
struct MyApp: App {
@State private var deepLinkTarget: String? = nil // State to hold the deep link target
var body: some Scene {
WindowGroup {
NavigationStack {
ContentView(deepLinkTarget: $deepLinkTarget) // Pass deepLinkTarget to ContentView
}
.onOpenURL { url in
// Deep linking logic to handle URL
if url.path == "/detail" {
deepLinkTarget = "DetailView"
}
}
}
}
}
struct ContentView: View {
@Binding var deepLinkTarget: String? // Binding to track deep link target
var body: some View {
NavigationStack {
VStack {
Text("Welcome to SwiftUI App!")
.font(.largeTitle)
.padding()
if deepLinkTarget == "DetailView" {
// If deep link is pointing to DetailView, navigate programmatically
NavigationLink(destination: DetailView(), isActive: .constant(true)) {
EmptyView()
}
}
}
.navigationTitle("Home")
}
}
}
struct DetailView: View {
var body: some View {
VStack {
Text("This is the Detail View!")
.font(.title)
Spacer()
}
.navigationTitle("Details")
}
}
- onOpenURL: This modifier gives our app the ability to handle URL scheme or universal link.
- Deep Link Handling: If the URL is /detail, we set deepLinkTarget, which then navigates to the DetailView.
Deep Linking with Dynamic Data:
If we need to pass dynamic data with deep link, we can use query parameters or path components.
import SwiftUI
@main
struct MyApp: App {
@State private var itemId: String? = nil // State to hold dynamic item ID
var body: some Scene {
WindowGroup {
NavigationStack {
ContentView(itemId: $itemId) // Pass itemId to ContentView
}
.onOpenURL { url in
// Handle deep link with dynamic data (e.g., item ID)
if url.path == "/item" {
if let itemId = url.queryParameters?["id"] {
self.itemId = itemId
}
}
}
}
}
}
struct ContentView: View {
@Binding var itemId: String? // Binding to hold item ID
var body: some View {
NavigationStack {
VStack {
Text("Welcome to the Item View!")
.font(.largeTitle)
.padding()
if let itemId = itemId {
NavigationLink("Go to Item \(itemId)", destination: ItemDetailView(itemId: itemId))
}
}
.navigationTitle("Home")
}
}
}
struct ItemDetailView: View {
var itemId: String // Dynamic item ID
var body: some View {
VStack {
Text("Item Details for ID: \(itemId)")
.font(.title)
.padding()
Spacer()
}
.navigationTitle("Item Details")
}
}
- Query Parameters: We read query parameters from URL through url.queryParameters?[“id”].
- Dynamic Data: Here itemId is being passed through deep link which is shown in ItemDetailView.
Leave a Reply