Mastering Swift UI- The Complete Guide (PART-4)

inspirethedev@gmail.com

State Management in SwiftUI

@State: Local View State

import SwiftUI

struct ContentView: View {
    @State private var counter = 0 // Local state to track counter
    
    var body: some View {
        VStack {
            Text("Counter: \(counter)") // Display counter value
                .font(.largeTitle)
                .padding()
            
            Button(action: {
                counter += 1 // Update the counter when button is pressed
            }) {
                Text("Increment Counter")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
}
  • @state: The counter is a local state maintained inside the ContentView. The view updates automatically when its value changes.

@Binding: Passing State Between Views

We use @Binding to pass the state of a parent view to a child view. This allows us to modify the state of one view directly in another view.

import SwiftUI

struct ContentView: View {
    @State private var counter = 0 // Parent state
    
    var body: some View {
        VStack {
            Text("Counter: \(counter)")
                .font(.largeTitle)
                .padding()
            
            // Passing counter to child view using @Binding
            ChildView(counter: $counter)
        }
    }
}

struct ChildView: View {
    @Binding var counter: Int // Binding to parent state
    
    var body: some View {
        Button(action: {
            counter += 1 // Modify the counter in parent view
        }) {
            Text("Increment Counter from Child")
                .font(.title)
                .padding()
                .background(Color.green)
                .foregroundColor(.white)
                .cornerRadius(10)
        }
    }
}

@ObservedObject: Observing External Data Changes

import SwiftUI
import Combine

class CounterModel: ObservableObject {
    @Published var counter = 0 // Observable data
    
    func increment() {
        counter += 1 // Method to update counter
    }
}

struct ContentView: View {
    @StateObject private var model = CounterModel() // Create an instance of CounterModel
    
    var body: some View {
        VStack {
            Text("Counter: \(model.counter)")
                .font(.largeTitle)
                .padding()
            
            Button(action: {
                model.increment() // Update the counter using model
            }) {
                Text("Increment Counter")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
}

@EnvironmentObject: Global State Management

Custom Animations and Transitions

Custom Animations Using Animation and withAnimation()

import SwiftUI

struct ContentView: View {
    @State private var scale: CGFloat = 1.0 // Initial scale
    
    var body: some View {
        VStack {
            Text("Tap to Scale")
                .font(.largeTitle)
                .padding()
            
            // Animated Circle
            Circle()
                .frame(width: 200, height: 200)
                .foregroundColor(.blue)
                .scaleEffect(scale) // Applying scale
                .animation(.easeInOut(duration: 1), value: scale) // Custom animation on scale
            
            Button(action: {
                // Trigger animation with `withAnimation()`
                withAnimation {
                    scale = scale == 1.0 ? 1.5 : 1.0 // Toggle scale value
                }
            }) {
                Text("Animate Circle")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
}

Combining Transitions for a Polished User Experience

import SwiftUI

struct ContentView: View {
    @State private var isVisible = false // State to control visibility
    
    var body: some View {
        VStack {
            Button(action: {
                withAnimation {
                    isVisible.toggle() // Toggle visibility with animation
                }
            }) {
                Text(isVisible ? "Hide Circle" : "Show Circle")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            
            // Animated Circle with Transition
            if isVisible {
                Circle()
                    .frame(width: 200, height: 200)
                    .foregroundColor(.green)
                    .transition(.scale) // Applying scale transition
            }
        }
    }
}

Combining Animations and Transitions for Complex Effects

import SwiftUI

struct ContentView: View {
    @State private var showCircle = false // State to toggle visibility
    
    var body: some View {
        VStack {
            Button(action: {
                withAnimation(.spring()) {
                    showCircle.toggle() // Toggle visibility with spring animation
                }
            }) {
                Text(showCircle ? "Hide Circle" : "Show Circle")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            
            if showCircle {
                Circle()
                    .frame(width: 200, height: 200)
                    .foregroundColor(.purple)
                    .transition(AnyTransition.scale.combined(with: .opacity)) // Combined transition
                    .animation(.easeInOut(duration: 1)) // Apply animation on combined transition
            }
        }
    }
}

Integrating UIKit with SwiftUI

What is UIViewControllerRepresentable and UIViewRepresentable?

Using UIViewControllerRepresentable

Step 1:Create a SwiftUI Wrapper for UIImagePickerController:

import SwiftUI
import UIKit

// UIViewControllerRepresentable ko conform karte hain
struct ImagePickerController: UIViewControllerRepresentable {
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        var parent: ImagePickerController
        
        init(parent: ImagePickerController) {
            self.parent = parent
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let selectedImage = info[.originalImage] as? UIImage {
                parent.selectedImage = selectedImage
            }
            parent.isImagePickerPresented = false
        }
        
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            parent.isImagePickerPresented = false
        }
    }
    
    @Binding var selectedImage: UIImage?
    @Binding var isImagePickerPresented: Bool

    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }
    
    // makeUIViewController method UIImagePickerController create karta hai
    func makeUIViewController(context: Context) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        picker.sourceType = .photoLibrary
        return picker
    }
    
    // updateUIViewController ko hum normally use nahi karte jab hum sirf image picker dikhane wale hain
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
}

Step 2: Usage in SwiftUI View:

struct ContentView: View {
    @State private var selectedImage: UIImage?
    @State private var isImagePickerPresented: Bool = false
    
    var body: some View {
        VStack {
            if let image = selectedImage {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 200, height: 200)
            } else {
                Text("Select an image")
            }
            
            Button("Open Image Picker") {
                isImagePickerPresented = true
            }
        }
        .sheet(isPresented: $isImagePickerPresented) {
            ImagePickerController(selectedImage: $selectedImage, isImagePickerPresented: $isImagePickerPresented)
        }
    }
}

Key Points to Remember

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *