SwiftUI is apple brand new UI framework.
- Drag and drop code (component & attributes )
- Easy Layouts VHZ Stack
- Cross apple plateform (WatchOS, iOS, iPadOS, MacOS)
Part 1 Build a SwiftUI App from scratch
How to Start you first SwiftUI
use SwiftUI modifiers to set properties for components
how to arrange elements using SwiftUI Stacks
how to add and size Image components
https://developer.apple.com/tutorials/swiftui/creating-and-combining-views
In xcode 12, you can choose App instead of single view app
Work with Xcode preview and the object library to generate SwiftUI code
Basic Layout:
cmd+click to embed element into vStack
Part 2 Create complex designs and layouts
- arrange elements to create complex layout
- add custom fonts to project
- work with RGB and HEX codes
- SF Symbols
- extract Subviews to create reusable SwiftUI components
Customize font
add font to plist
Create a new group and drag font.ttf to the group
SF Symbols
Make it reusable
cmd+click to choose subview, xcode will automatically generate code for subview and we can rename it.
To make it reusable, we can create two variables
In order to keep our code neat, often we would create a new file which is a SwiftUIView
the defaut preview layout is a phone but to make it as large as our reusbale component we can use .previewLayout(.sizeThatFits) to fit our size.
Part 3 Building in Functionality and Managing state
Spacer
State
Allow us to update variables and rerender when the variables are updated
In swift we can use mutating but in swiftUI we need to use @State, because SwiftUI is declare programming like react.
Part 4 List, Identifiable Protocol, Networking and Oberver Design Pattern
- SwiftUI Lists and Identifiable Protocol
- Navigation View to navigate between the List and detail view
- Adance State management using the Observer Design Pattern
- incorporate a UIKit component into SwiftUI by using WebKit to display web pages
nav, list, identifiable protocol
identifiable protocol can make our list to be able to order items, and the identifiable struct must have a id variable
List render from Identifiable Protocol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// // ContentView.swift // HackerNews // // Created by Bing Xiong on 12/3/20. // import SwiftUI struct ContentView: View { var body: some View { NavigationView{ List(posts) { post in Text(post.title) } .navigationTitle("Haker News") } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } struct Post: Identifiable { let id: String let title: String } let posts = [ Post(id: "1", title: "Hello"), Post(id: "2", title: "Bonjour"), Post(id: "3", title: "Hola") ] |
NetWorking:
- @ObservedObject
- @Published
- DispatchQueue.main.async
- Decode json
ContentView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import SwiftUI struct ContentView: View { @ObservedObject var networkManger = NetworkManager() var body: some View { NavigationView{ List(networkManger.posts) { post in HStack { Text(String(post.points)) Text(post.title) } } .navigationTitle("Haker News") } .onAppear(perform: { self.networkManger.fetchData() }) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } |
PostData.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import Foundation struct Results: Decodable { let hits: [Post] } struct Post: Decodable, Identifiable { var id: String { return objectID } let objectID: String let points: Int let title: String let url: String? } |
NetworkManager.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import Foundation class NetworkManager: ObservableObject { @Published var posts = [Post]() func fetchData() { if let url = URL(string: "https://hn.algolia.com/api/v1/search?tags=front_page"){ let session = URLSession(configuration: .default) let task = session.dataTask(with: url){(data, response, error) in if error == nil { let decoder = JSONDecoder() if let safeData = data{ do { let results = try decoder.decode(Results.self, from: safeData) DispatchQueue.main.async { self.posts = results.hits } } catch { print("error") } } } } task.resume() } } } |
Add links to a list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
var body: some View { NavigationView{ List(networkManger.posts) { post in NavigationLink( destination: DetailView(url: post.url)){ HStack { Text(String(post.points)) Text(post.title) } } } .navigationTitle("Haker News") } .onAppear(perform: { self.networkManger.fetchData() }) } |
WebView:
SwiftUI doesn’t have webview component, we can create a struct to comform UIViewRepresentable and Implement two delegate method
WebView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import SwiftUI import WebKit import Foundation struct WebView: UIViewRepresentable { let urlString: String? func makeUIView(context: Context) -> WKWebView { return WKWebView() } func updateUIView(_ uiView: WKWebView, context: Context) { if let safeString = urlString { if let url = URL(string: safeString){ let request = URLRequest(url: url) uiView.load(request) } } } } |
And use the reusable UIKit based component in swiftUI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// // DetailView.swift // HackerNews // // Created by Bing Xiong on 12/3/20. // import SwiftUI struct DetailView: View { let url: String? var body: some View { WebView(urlString: url) } } struct DetailView_Previews: PreviewProvider { static var previews: some View { DetailView(url: "") } } |