30 Days of SwiftUI - Day 22: SwiftUI Challenge Day: Data Filtering, Grids, and Navigation Mastery!
Hello Swift learners! Today, we're putting our knowledge to the test with some practical questions based on what we've learned in the past few days. Let's sharpen our skills and solidify our understanding of iExpense, grids, and navigation.
Practical Tests
Test 1: Enhanced iExpense
Question: Create a SwiftUI view that displays a list of numbers from 1 to 20. Add a Toggle
that allows the user to filter the list to show only even numbers.
Test 2: Dynamic Grid with Image Loading
Question: Create a SwiftUI view with a LazyVGrid
that displays images from an array of image URLs. Load the images asynchronously and display a placeholder while the images are loading.
Test 3: Navigation with Path Persistence
Question: Create a navigation stack that allows users to navigate to detail views based on strings and integers. Implement the ability to save and load the navigation path using UserDefaults
and Codable
.
Answers and Complete SwiftUI Code
Answer 1: Data Filtering
import SwiftUI
struct DataFilterTest: View {
@State private var showEvenNumbers = false
var body: some View {
VStack {
Toggle("Show Even Numbers", isOn: $showEvenNumbers)
.padding()
List {
ForEach(1...20, id: \.self) { number in
if !showEvenNumbers || number.isMultiple(of: 2) {
Text("\(number)")
}
}
}
}
}
}
struct DataFilterTest_Previews: PreviewProvider {
static var previews: some View {
DataFilterTest()
}
}
Answer 2: Dynamic Grid with Image Loading
import SwiftUI
struct ImageGrid: View {
let imageURLs = [
"https://source.unsplash.com/random/200x200",
"https://source.unsplash.com/random/201x201",
"https://source.unsplash.com/random/202x202",
"https://source.unsplash.com/random/203x203"
]
let columns = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 10) {
ForEach(imageURLs, id: \.self) { urlString in
AsyncImage(url: URL(string: urlString)) { image in
image.resizable().scaledToFit()
} placeholder: {
ProgressView()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100)
.background(Color.gray.opacity(0.3))
.cornerRadius(8)
}
}
.padding()
}
}
}
struct ImageGrid_Previews: PreviewProvider {
static var previews: some View {
ImageGrid()
}
}
Answer 3: Navigation with Path Persistence
import SwiftUI
struct NavigationPathData: Codable {
let path: [AnyCodable]
}
struct AnyCodable: Codable {
let value: Any
init<T: Codable>(_ value: T) {
self.value = value
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let intValue = try? container.decode(Int.self) {
self.value = intValue
} else if let stringValue = try? container.decode(String.self) {
self.value = stringValue
} else {
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unsupported type"))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
if let intValue = value as? Int {
try container.encode(intValue)
} else if let stringValue = value as? String {
try container.encode(stringValue)
}
}
}
struct NavigationPersistenceTest: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
VStack {
Button("Push String") {
path.append("Hello")
}
Button("Push Number") {
path.append(42)
}
Button("Save Path") {
savePath()
}
Button("Load Path") {
loadPath()
}
}
.navigationTitle("Main View")
.navigationDestination(for: String.self) { text in
Text("String: \(text)")
}
.navigationDestination(for: Int.self) { number in
Text("Number: \(number)")
}
}
}
func savePath() {
let codablePath = NavigationPathData(path: path.map { AnyCodable($0 as! Codable) })
if let encoded = try? JSONEncoder().encode(codablePath) {
UserDefaults.standard.set(encoded, forKey: "navigationPath")
}
}
func loadPath() {
if let data = UserDefaults.standard.data(forKey: "navigationPath") {
if let decoded = try? JSONDecoder().decode(NavigationPathData.self, from: data) {
path = NavigationPath(decoded.path.map { $0.value })
}
}
}
}
struct NavigationPersistenceTest_Previews: PreviewProvider {
static var previews: some View {
NavigationPersistenceTest()
}
}
Key Takeaways
- iExpense Enhancement: We added filtering to the iExpense app, demonstrating practical data manipulation.
- Dynamic Grids: We created a dynamic grid with asynchronous image loading, showcasing how to handle external data.
- Navigation Persistence: We implemented navigation path persistence, reinforcing how to save and load complex data structures.
By working through these practical tests, you've strengthened your understanding of key SwiftUI concepts. Keep practicing, and you'll be building more complex and engaging apps in no time!
Follow me on Linkedin: igatitech 🚀🚀🚀
Comments
Post a Comment