Open14
[SwiftUI] PizzaApp
[View]HomeView
まずHomeViewを作る。
[Model]Pizza
[View]HomeView
tabViewでピザの生地をスワイプできるようにした。
[View]HomeView
サイズについて現在選択しているものが浮かび上がるようにした。
[View]HomeView
ピザの大きさに合わせていろいろ動くようにした。
サイズはeurm型に入れた。
それをForEachでsizeに入れる。
Buttonで現在認識しているsizeを取得させていい感じに動かす。
[View]HomeView
トッピング画像の表示。
[View]HomeView
カートに追加するButton。
[Model] Topping
[View]HomeView
まずPizzaのindexを取ってくる。
インデックスを検索し、トッピングを追加&削除する。
ランダムに配置。
struct ~ var body: some View
- @State var pizzas: [Pizza] = [ ] でPizza配列を作成。
- ピザ生地の初期値を @State var currentPizza: String = "Bread_1" とする。
- サイズの初期値をmediumにする。
- @Namespace var animation
- toppings配列を定義
- ヘッダー画像関係のコードをアクセス修飾詞fileprivateで囲う。func extractedFunc。
ヘッダー Image
- VStack ヘッダー 〜 サイズ選択部分まで囲う。
- extractedFunc()
- VStack内にGometryReaderを設置。取得したViewサイズ = インスタンスsizeに入れる。
- ZstadeでAssetsのPlateを配置。
スワイプでピザの切り替え
- TabView(selection: $currentPizza) { ForEach ...
現在選択しているPizza画像を認識する挙動
- まだここはVStack,ZStack配下。
- ZStack上にTabViewを形成する。
- TabView内にもZStackを設置し、ピザ生地とトッピングを一体の画像として配置できるようにする。
- 子ViewとしてPizza配列にいるbreadNameで識別できるImageを設定する。
- 別で定義した関数 ToppingsViewを設置。
- ピザ生地とトッピングの入っているZStackのモディファーとして
.scaleEffect
とtag
を設置。 - enum型に入っているサイズS,M,Lの変動に合わせて、.largeだったら1,.mediumだったら0.95,それでもなかったら0.09にサイズを変更させる。
関数 ToppingsView
- トッピングの画像の挙動を定義している関数。
- Groupで全体を大きく囲う。
- ForEachでトッピング配列を回す。この時.indicesをつける。
ForEach () { in ...
ForEach(toppings.indices,id: \.self){index in
//各トッピングは10枚のトッピング画像から構成される
let topping = toppings[index]
-
.indices
は配列のアクセスできる範囲を示している。 - トッピングがランダムに配置できるようにしたい。
- 先のForEach配下にForEachをもう一つ作成する。
- トッピング20個配置。
ForEach(1...20,id: \.self){subIndex in
// 360/10 = 36....
let rotation: Double = Double(subIndex) * 36
let crtIndex = (subIndex > 10 ? (subIndex - 10) : subIndex)
Image("\(topping.toppingName)_\(crtIndex)")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
//インデックスは0から始まる
.offset(x: (width / 2) - topping.randomToppingPostions[subIndex - 1].width,y: topping.randomToppingPostions[subIndex - 1].height)
.rotationEffect(.init(degrees: rotation))
// 360回転でランダムな位置にToppingを展開する.
//offset(x:y:)指定された水平および垂直距離だけ、このビューをずらして配置
//.rotationEffectで回転を動きに加えている。
}
- let rotation: Double = Double(subIndex) * 36
- let crtIndex = (subIndex > 10 ? (subIndex - 10) : subIndex)
- Imageを指定。トッピング画像グループは10までしか登録されていないので crtIndexを用いる。
- offsetでtopping.randomToppingPostionsに紐づけられているCGSizeを取得する。
- .rotationEffect(.init(degrees: rotation))で回転
widthには
VStack {
GeometryReader{proxy in
let size = proxy.size
//ヘッダー、プレート、トッピング&ピザのVIew (値段より上の部分)
}
}
の、size
が入っている。
ofset1
.offset(x: topping.randomToppingPostions[subIndex - 1].width,y: (width / 2) - topping.randomToppingPostions[subIndex - 1].height)
offset2
.offset(x: topping.randomToppingPostions[subIndex - 1].width,y: topping.randomToppingPostions[subIndex - 1].height)
offset3
.offset(x: (width / 2) - topping.randomToppingPostions[subIndex - 1].width,y: (width / 2) - topping.randomToppingPostions[subIndex - 1].height)
offset4
.offset(x: (width / 2) - topping.randomToppingPostions[subIndex - 1].width,y: topping.randomToppingPostions[subIndex - 1].height)
.rotationEffectをコメントアウト
let rotation: Double = Double(subIndex) * 36
let crtIndex = (subIndex > 10 ? (subIndex - 10) : subIndex)
Image("\(topping.toppingName)_\(crtIndex)")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
//インデックスは0から始まる
.offset(x: (width / 2) - topping.randomToppingPostions[subIndex - 1].width,y: topping.randomToppingPostions[subIndex - 1].height)
// .rotationEffect(.init(degrees: rotation))
回転の挙動は .rotationEffectが担っている。。。?
引き続き関数 ToppingsView の中身を見る。
- .scaleEffectでViewの拡大縮小の動き。
- 上からトッピング画像が落ちてくるという挙動になっているが、まずここでtoppingを10倍の大きさにする。
- .scaleEffectはtoppingのBool値が trueだったら作動する。
- .onAppear以下でトッピングがタップされた直後のアニメーションを書いている。
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.08) {}
- 括弧内にwithAnimation