SwiftUI - Brief Introduction with Samples

Apple iOS is the operating system for iPhone, iPad, and other Apple mobile devices

SwiftUI is a new way to build user interfaces UIs for apps on Apple platforms using Swift code

SwiftUI which is a declarative framework you simply tell SwiftUI what you want and then let the framework do it for you

1. Prerequisites

1.1. How to create a Virtual Machine with VirtuaBox for installing Mac Sonoma

See this github repo for a detailed explanation: https://github.com/luiscoco/macOS_Sonoma_VMWare/tree/main

1.2. How to install XCode 15 in Mac

See this youtube video: https://www.youtube.com/watch?v=F6QZ2atZrDw&t=90s

2. Learning by doing applications

2.1. My First Application with SwiftUI

See the application running in the IPhone simulator

image

See myfirstapp code

import SwiftUI

@main
struct myfirstappApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

See the ContentView code

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

2.2. Simple Counter App (State management)

This app will help you understand the basics of state management in SwiftUI

image

import SwiftUI

struct ContentView: View {
    @State private var counter = 0
    
    var body: some View {
        VStack {
            Text("Counter: \(counter)")
                .font(.largeTitle)
                .padding()
            
            HStack {
                Button(action: {
                    counter -= 1
                }) {
                    Text("-")
                        .font(.largeTitle)
                        .padding()
                        .background(Color.red)
                        .foregroundColor(.white)
                        .cornerRadius(10)
                }
                
                Button(action: {
                    counter += 1
                }) {
                    Text("+")
                        .font(.largeTitle)
                        .padding()
                        .background(Color.green)
                        .foregroundColor(.white)
                        .cornerRadius(10)
                }
            }
        }
    }
}

@main
struct CounterApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

2.3. TodoList App (List)

This app demonstrates how to use lists and manage data with a simple todo list

image

import SwiftUI

struct TodoItem: Identifiable {
    let id = UUID()
    let title: String
}

struct ContentView: View {
    @State private var items = [TodoItem]()
    @State private var newItemTitle = ""
    
    var body: some View {
        NavigationView {
            VStack {
                HStack {
                    TextField("New item", text: $newItemTitle)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                    
                    Button(action: {
                        let newItem = TodoItem(title: newItemTitle)
                        items.append(newItem)
                        newItemTitle = ""
                    }) {
                        Text("Add")
                            .padding()
                            .background(Color.blue)
                            .foregroundColor(.white)
                            .cornerRadius(10)
                    }
                }
                
                List(items) { item in
                    Text(item.title)
                }
            }
            .navigationTitle("Todo List")
        }
    }
}

2.4. Weather App (Fetch mock data)

This app shows how to fetch and display data from a web API. For simplicity, we will use mock data

image

import SwiftUI

struct Weather: Identifiable {
    let id = UUID()
    let day: String
    let temperature: Int
}

struct ContentView: View {
    let weatherData = [
        Weather(day: "Monday", temperature: 22),
        Weather(day: "Tuesday", temperature: 25),
        Weather(day: "Wednesday", temperature: 19),
        Weather(day: "Thursday", temperature: 23),
        Weather(day: "Friday", temperature: 21)
    ]
    
    var body: some View {
        NavigationView {
            List(weatherData) { weather in
                VStack(alignment: .leading) {
                    Text(weather.day)
                        .font(.headline)
                    Text("\(weather.temperature)°C")
                        .font(.subheadline)
                }
            }
            .navigationTitle("Weather Forecast")
        }
    }
}

@main
struct WeatherApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

2.5. Form and Data Binding

image

import SwiftUI

struct ContentView : View {
    @State private var username: String = ""
    @State private var notificationsEnabled: Bool = true
    @State private var selectedColor: Color = .blue
    
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Profile")) {
                    TextField("Username", text: $username)
                }
                
                Section(header: Text("Preferences")) {
                    Toggle("Enable Notifications", isOn: $notificationsEnabled)
                    
                    ColorPicker("Favorite Color", selection: $selectedColor)
                }
                
                Section {
                    Button(action: {
                        // Handle save action
                    }) {
                        Text("Save")
                    }
                }
            }
            .navigationTitle("Settings")
        }
    }
}

@main
struct UserSettingsApp: App {
    var body: some Scene {
        WindowGroup {
            UserSettings()
        }
    }
}

2.6. Animation

image

image

import SwiftUI

struct ContentView : View {
    @State private var isExpanded = false
    
    var body: some View {
        VStack {
            Circle()
                .frame(width: isExpanded ? 200 : 100, height: isExpanded ? 200 : 100)
                .foregroundColor(isExpanded ? .green : .blue)
                .animation(.easeInOut(duration: 1), value: isExpanded)
            
            Button(action: {
                isExpanded.toggle()
            }) {
                Text("Animate")
                    .padding()
                    .background(Color.black)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
}

@main
struct AnimatedCircleApp: App {
    var body: some Scene {
        WindowGroup {
            AnimatedCircle()
        }
    }
}

2.7. Custom Views

image

import SwiftUI

struct CustomCardView: View {
    var title: String
    var subtitle: String
    var backgroundColor: Color
    
    var body: some View {
        VStack(alignment: .leading) {
            Text(title)
                .font(.headline)
                .foregroundColor(.white)
            
            Text(subtitle)
                .font(.subheadline)
                .foregroundColor(.white)
        }
        .padding()
        .background(backgroundColor)
        .cornerRadius(10)
        .shadow(radius: 5)
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            CustomCardView(title: "Card 1", subtitle: "This is the first card", backgroundColor: .blue)
            CustomCardView(title: "Card 2", subtitle: "This is the second card", backgroundColor: .green)
            CustomCardView(title: "Card 3", subtitle: "This is the third card", backgroundColor: .red)
        }
        .padding()
    }
}

@main
struct CustomViewsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

2.8. Networking with URLSession

image

import SwiftUI

struct Post: Codable, Identifiable {
    let id: Int
    let title: String
    let body: String
}

struct ContentView: View {
    @State private var posts = [Post]()
    
    var body: some View {
        NavigationView {
            List(posts) { post in
                VStack(alignment: .leading) {
                    Text(post.title)
                        .font(.headline)
                    Text(post.body)
                        .font(.subheadline)
                }
            }
            .navigationTitle("Posts")
            .onAppear {
                fetchPosts()
            }
        }
    }
    
    func fetchPosts() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else {
            return
        }
        
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data {
                do {
                    let decodedPosts = try JSONDecoder().decode([Post].self, from: data)
                    DispatchQueue.main.async {
                        self.posts = decodedPosts
                    }
                } catch {
                    print("Error decoding data: \(error)")
                }
            }
        }.resume()
    }
}

@main
struct NetworkingApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

3. Additional information

https://en.wikipedia.org/wiki/SwiftUI

https://developer.apple.com/tutorials/swiftui-concepts

https://developer.apple.com/tutorials/swiftui

https://developer.apple.com/tutorials/sample-apps

https://github.com/ArisGuimera/iOS-Expert

https://www.hackingwithswift.com/quick-start/swiftui

https://www.youtube.com/watch?v=f6WtmTBFNGM&t=10376s

CURSO: SWIFT y SWIFTUI desde CERO en ESPAÑOL - Programación IOS - TUTORIAL XCODE:

https://www.youtube.com/watch?v=f6WtmTBFNGM&list=PL8ie04dqq7_MeCR8iYIy_eumrYK7JzuPJ