このプロジェクトの最初のステップは、注文の基本的な詳細(注文するカップケーキの数、注文する種類、特別なカスタマイズがあるかどうか)を示す注文画面を作成することです。
以前は@State、単純な値の型と@ObservedObject参照の型に使用しており、ObservableObject構造体を含むクラスを作成して、両方の利点を得る方法を見てきました。
ここでは、別のソリューションを使用します。画面間で渡されるすべてのデータを格納する単一のクラスを作成します。これは、アプリのすべての画面が同じデータを共有することを意味します。
didSetプロパティオブザーバー
import SwiftUI
class Order: ObservableObject {
static let types = ["Vanilla", "Strawberry", "Chocolate", "Rainbow"]
@Published var type = 0
@Published var quantity = 3
//@Published var specialRequestEnabled = false
@Published var specialRequestEnabled = false {
didSet {
if specialRequestEnabled == false {
extraFrosting = false
addSprinkles = false
}
}
}
@Published var extraFrosting = false
@Published var addSprinkles = false
}
import SwiftUI
struct ContentView: View {
@ObservedObject var order = Order()
var body: some View {
NavigationView {
Form {
Section {
Picker("Select your cake type", selection: $order.type) {
//ForEach(0..<Order.types.count) {
ForEach(0..<Order.types.count, id: \.self) {
Text(Order.types[$0])
}
}
Stepper(value: $order.quantity, in: 3...20) {
Text("Number of cakes: \(order.quantity)")
}
}
Section {
Toggle(isOn: $order.specialRequestEnabled.animation()) {
Text("Any special requests?")
}
if order.specialRequestEnabled {
Toggle(isOn: $order.extraFrosting) {
Text("Add extra frosting")
}
Toggle(isOn: $order.addSprinkles) {
Text("Add extra sprinkles")
}
}
}
Section {
NavigationLink(destination: AddressView(order: order)) {
Text("Delivery details")
}
}
}
.navigationBarTitle("Cupcake Corner")
}
}
}
import SwiftUI
struct AddressView: View {
@ObservedObject var order: Order
var body: some View {
Text("Hello World")
}
}
struct AddressView_Previews: PreviewProvider {
static var previews: some View {
AddressView(order: Order())
}
}
有効な住所を確認する
Checking for a valid address
import SwiftUI
class Order: ObservableObject {
static let types = ["Vanilla", "Strawberry", "Chocolate", "Rainbow"]
@Published var type = 0
@Published var quantity = 3
//@Published var specialRequestEnabled = false
@Published var specialRequestEnabled = false {
didSet {
if specialRequestEnabled == false {
extraFrosting = false
addSprinkles = false
}
}
}
@Published var extraFrosting = false
@Published var addSprinkles = false
//--------------------------------
@Published var name = ""
@Published var streetAddress = ""
@Published var city = ""
@Published var zip = ""
var hasValidAddress: Bool {
if name.isEmpty || streetAddress.isEmpty || city.isEmpty || zip.isEmpty {
return false
}
return true
}
}
import SwiftUI
struct AddressView: View {
@ObservedObject var order: Order
var body: some View {
Form {
Section {
TextField("Name", text: $order.name)
TextField("Street Address", text: $order.streetAddress)
TextField("City", text: $order.city)
TextField("Zip", text: $order.zip)
}
Section {
NavigationLink(destination: CheckoutView(order: order)) {
Text("Check out")
}
}
.disabled(order.hasValidAddress == false)
}
.navigationBarTitle("Delivery details", displayMode: .inline)
}
}
struct AddressView_Previews: PreviewProvider {
static var previews: some View {
AddressView(order: Order())
}
}
import SwiftUI
struct CheckoutView: View {
@ObservedObject var order: Order
var body: some View {
Text("Hello, World!")
}
}
struct CheckoutView_Previews: PreviewProvider {
static var previews: some View {
CheckoutView(order: Order())
}
}
import SwiftUI
struct ContentView: View {
@ObservedObject var order = Order()
var body: some View {
NavigationView {
Form {
Section {
Picker("Select your cake type", selection: $order.type) {
//ForEach(0..<Order.types.count) {
ForEach(0..<Order.types.count, id: \.self) {
Text(Order.types[$0])
}
}
Stepper(value: $order.quantity, in: 3...20) {
Text("Number of cakes: \(order.quantity)")
}
}
Section {
Toggle(isOn: $order.specialRequestEnabled.animation()) {
Text("Any special requests?")
}
if order.specialRequestEnabled {
Toggle(isOn: $order.extraFrosting) {
Text("Add extra frosting")
}
Toggle(isOn: $order.addSprinkles) {
Text("Add extra sprinkles")
}
}
}
Section {
NavigationLink(destination: AddressView(order: order)) {
Text("Delivery details")
}
}
}
.navigationBarTitle("Cupcake Corner")
}
}
}
CheckoutView
OrderクラスをJSON にエンコードし、インターネット経由で送信して、応答を取得する
チェックアウトの準備
Preparing for checkout
import SwiftUI
class Order: ObservableObject {
static let types = ["Vanilla", "Strawberry", "Chocolate", "Rainbow"]
@Published var type = 0
@Published var quantity = 3
//@Published var specialRequestEnabled = false
@Published var specialRequestEnabled = false {
didSet {
if specialRequestEnabled == false {
extraFrosting = false
addSprinkles = false
}
}
}
@Published var extraFrosting = false
@Published var addSprinkles = false
//--------------------------------
@Published var name = ""
@Published var streetAddress = ""
@Published var city = ""
@Published var zip = ""
var hasValidAddress: Bool {
if name.isEmpty || streetAddress.isEmpty || city.isEmpty || zip.isEmpty {
return false
}
return true
}
var cost: Double {
// $2 per cake
var cost = Double(quantity) * 2
// complicated cakes cost more
cost += (Double(type) / 2)
// $1/cake for extra frosting
if extraFrosting {
cost += Double(quantity)
}
// $0.50/cake for sprinkles
if addSprinkles {
cost += Double(quantity) / 2
}
return cost
}
}
import SwiftUI
struct CheckoutView: View {
@ObservedObject var order: Order
var body: some View {
GeometryReader { geo in
ScrollView {
VStack {
Image("cupcakes")
.resizable()
.scaledToFit()
.frame(width: geo.size.width)
Text("Your total is $\(self.order.cost, specifier: "%.2f")")
.font(.title)
Button("Place Order") {
// place the order
}
.padding()
}
}
}
.navigationBarTitle("Check out", displayMode: .inline)
}
}