SwiftUI
Icon
Image(systemName: "star.fill").imageScale(.medium).foregroundColor(.yellow)
Bool
bool.toggle()
Binding
@State private var isPlaying: Bool = false
PlayButton(isPlaying: $isPlaying)
struct PlayButton : View {
@Binding var isPlaying: Bool
OnReceive
.onReceive(PodcastPlayer.currentTimePublisher) { newCurrentTime in
self.currentTime = newCurrentTime
}
Weak
DispatchQueue.main.async { [weak self] in
DispatchQueue.global(qos: .background).async { [weak self] in
guard let strongSelf = self else { return }
weak var owner: Person?
https://www.appcoda.com/memory-management-swift/
Product > Profile > Leaks
UI Tweaking
.padding([.leading, .trailing])
.font(.caption)
HStack {
Text("Delicious")
Image("20x20_avocado")
Text("Avocado Toast").layoutPriority(1) // so it will not be compressed when HStack width is not enough
}
.lineLimit(1)
237_building_custom_views_with_swiftui.pdf
// Animation and draw grphaic
List(previousOrders) { order in
HStack {
VStack(alignment: .leading) {
Text(order.summary)
Text(order.purchaseDate)
.font(.subheadline)
.foregroundColor(.secondary)
}
Spacer()
if order.includeSalt {
SaltIcon()
}
}
}
struct IconOrientationEditor : View {
let flipped: Bool
var body: some View {
ZStack {
Color.gray
AppIcon()
.rotationEffect(.degrees(flipped ? 180 : 0))
}
}
}
Form {
Button(action: submitOrder) { Text("Order") }
Section(header: ) { Text("Avocado Toast").font(.title)
}.
Toggle(isOn: $order.includeSalt) { }
Toggle(isOn: $order.includeRedPepperFlakes) { }
Stepper(value: $order.quantity, in: 1...10) { }
}
Section {
Button(action: submitOrder) { Text("Order") }
}
}
Button(action: submitOrder) {
VStack {
Image("Toast")
Text("Order")
}
}
@State private var order: Order
struct Order {
enum Spread : CaseIterable, Hashable, Identifiable {
case none
case almondButter
case peanutButter
case honey
case almou
case tapenade
case hummus
case mayonnaise
case kyopolou
case adjvar
case pindjur
case vegemite
case chutney
case cannedCheese
case feroce
case kartoffelkase
case tartarSauce
}
Picker(selection: $order.spread, label: Text("Spread")) {
ForEach(Spread.allCases) { spread in
Text(spread.name).tag(spread)
}.
}
Button(action: submitOrder) { Text("Order") }
.disabled(order.quantity == 0)
Toggle(isOn: $order.includeSalt) {}
Form {}
.accentColor(Color("avocadoGreen"))
.disabled(!connectedToToastNetwork)
216_swiftui_essentials.pdf
Combine
@Published var username: String = ""
var validatedUsername: AnyPublisher<String?, Never> {
return $username
.debounce(for: 0.5, scheduler: RunLoop.main)
.removeDuplicates()
.flatMap { username in
return Future { promise in
self.usernameAvailable(username) { available in
promise(.success(available ? username : nil))
}
}
}
.eraseToAnyPublisher()
}
@Published var password: String = ""
@Published var passwordAgain: String = ""
var validatedPassword: AnyPublisher<String?, Never> {
return CombineLatest($password, $passwordAgain) { password, passwordAgain in
guard password == passwordAgain, password.count > 8 else { return nil }
return password
}
.map { $0 == "password1" ? nil : $0 }
.eraseToAnyPublisher()
}
var validatedCredentials: AnyPublisher<(String, String)?, Never> {
return CombineLatest(validatedUsername, validatedPassword) { username, password in
guard let uname = username, let pwd = password else { return nil }
return (uname, pwd)
}
.eraseToAnyPublisher()
}
@IBOutlet var signupButton: UIButton!
var signupButtonStream: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
self.signupButtonStream = self.validatedCredentials
.map { $0 != nil }
.receive(on: RunLoop.main)
.assign(to: \.isEnabled, on: signupButton)
}
Resources
- https://www.jianshu.com/p/441930138de2
- https://fuckingswiftui.com/
- https://www.hackingwithswift.com/quick-start/swiftui
- https://www.hackingwithswift.com/100/swiftui
- https://swiftui-lab.com/
- https://swiftui-lab.com/custom-styling/