初心者プログラミング日記 SwiftUI②
//
// SandwichDetail.swift
// Landmarks
//
//
//SwiftUIはUIを定義する
import SwiftUI
//SwiftUIのViewの在り方
//SwiftUIではViewはViewプロトコルに準拠する構造体で基本クラスを継承しない
//つまり保存されているプロパティを継承せず、Viewはスタックに割り当てされて、位置情報等の値を渡される
//SandwichDetailにはサイズや重さだけが保存されていて、
//追加の割り当てや参照カウントはありません(たぶんUnitiyでいうUpdate()みたいな機能)
//SwiftUIは裏でViewの階層を積極的にまとめて、レンダリング用のデータを作る。
//そのためSwiftUIでは小さな単一目的のビューを自由に使える。
//サブViewの抽出に余計な作業がないためリファクタリング(プログラム内の整理)時に外部構造を考慮する必要が少ない
//SwiftUIはレンダリングのタイミングをプログラムの依存関係から把握している。
//状態変数とモデルが合わさってApp全体の単一の信頼できる情報源を構成する。
//情報源が複数にあると、実装忘れ等不具合の温床になるという考え方
//全てのプロパティは情報源かその派生値かに分類できる
//状態変数(State):Source of truth(get,set)
//変数(var) :読み取り専用派生値(get)
//binding :読み書き可能な派生値(get,set)
//定数(let) :読み取り専用のSource of truth
//ObservableObject :状態変数とモデルで構成されたApp全体のSource of Truth
//MVVM(Model View ViewModel)はコードデザインのパターン
//ModelとViewを分離することに主眼を置いている
//View :ユーザー接点(イベント) ー構造体
//Model :プログラム ー構造体
//ViewModel :ユーザー接点とプログラムを仲介するコード ークラス
struct SandwichDetail: View {
var sandwich: Sandwich //親Viewで渡される派生値(読み取り専用)
//状態変数_View実装内で読み書き変更可能
//状態変数を持つViewはViewの代わりに変数にストレージが割り当てられる
//SwiftUIは状態変数の読み取りや書き込みを観測できる
//変数の変更に伴いフレームワークは再度bodyを要求し、
//新たな状態値を用いてレンダリングを更新する
@State private var zoomed = false
var body: some View {
VStack {
Spacer(minLength: 0) //要素間の余白を維持するため自動的に最小になる
Image(sandwich.thumbnailName)
.resizable()
.aspectRatio(contentMode: zoomed ? .fill : .fit)
.onTapGesture {
//アニメーションを入れる
withAnimation{
zoomed.toggle()
}
}
Spacer(minLength: 0)
//もしスパイシーな場合ならバナーを表示
//拡大表示の場合もバナーは非表示
if sandwich.isSpicy && !zoomed{
//画面下部に背景がある下部バナーを作る
//SwiftUIではコンテンツに合わせて表示サイズが調整される
HStack {
Spacer()
Label ("Spicy", systemImage:"flame.fill")
.padding(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
Spacer()
}
//シンボルサイズも大きくなるので注意
//スモールキャップ(小文字サイズの大文字書体)もつける
.font(Font.headline.smallCaps())
.foregroundColor(Color.yellow)//文字色黄色
.background(Color.red)//単色背景
.transition(.move(edge: .bottom))//アニメーションをつける
}
}
.navigationTitle(sandwich.name)
//エッジまで表示
.edgesIgnoringSafeArea(.bottom)
}
}
struct SandwichDetail_Previews: PreviewProvider {
static var previews: some View {
Group {
NavigationView{
SandwichDetail(sandwich: testData[0])
}
NavigationView{
SandwichDetail(sandwich: testData[6])
}
}
}
}
//SwiftUI:View自体が持続し依存関係を自動的に管理して、全てを最新かつ一貫性のある状態に保っている。
//適切な派生値を計算してバグが何度も発生しないようにする。
//Viewの更新を1つのメソッドに収集して単純化している。メソッドが1つなら呼び出せる組み合わせは1通り。
//bodyを唯一のエントリポイントにして、フレームワークにコード化している。(抽象化)
//サブViewの削除、Navigation Stackへのプッシュ、テーブルビューへの更新の実行など。
//View,App,Scene,bodyを含むその他のSwiftUIの抽象化が機能する。
//変化したUIの新しいインスタンスを単純に取り出すことで解決している。
//従来:Viewがデータを読み取るたびに依存関係になる。
//データの変更に応じてViewを更新して新しい値を反映する必要があるので、失敗すると何度もバグになる。
//複数の依存関係が複雑に発生すると、人が管理できる限界を越える。
//例)ズームすると拡大ボタンが表示→低解像度の画像が表示→ボタンを押す
//→機械学習操作がバックグラウンドスレッドに送られて画質を向上させる。
//イベントを把握するためのコールバックでバグが起きることが多くイベントの組み合わせの数だけ発生する
//とすればとても把握できるものではない。割り込みやアニメーション、並行処理まで入ってくると複雑さは未知数。
下部バナーアニメーションに利用したtransitionでは何が起こっているのか。
ズームによりバナーを削除すると、Viewは新しい位置のオフスクリーンにアニメーション化される。SwiftUIはアニメーション終了まで待機して階層からViewを実際に削除する。
そして戻った時にSwiftUIがオフスクリーンを挿入し、アニメーションで元の位置に戻す。
アニメーションを使用し階層構造からビューの追加や削除が簡単にできる。
このアニメーションは箱から出してすぐに双方向やりとりできる。
イベント駆動型(何かアクションがあったら動く)ではなく、データ駆動型(別のデータ連動で動く)の長所。
通常、OSには画面表示が行われないフレームバッファがありそれをオフスクリーンバッファという。オフスクリーンとはそのオフスクリーンバッファにレンダリングしていること。
初心者プログラミング日記 SwiftUI①
WWDC20「introduction to SwiftUI」を勉強中
会計学科というド文系の下記独学でイマココな感じです笑
初心者用の教本1冊→自作TODOアプリ作ろうとしてあと一歩のところでどれも断念
→Unityに2Dアプリ制作に逃げる→再度SwiftUI←イマココ
なかなかSwiftUIの日本人にわかりやすい教材がなく苦戦していました。
下記は字幕が日本語で出て、意味も取れるのでやってみることにしました。
プログラミングなのでプログラム内にコメントを残していたのですが、
SwiftUIの特徴も合わせて説明してくれるので、溢れてきたのでこちらにメモとして
残すことにしました。
//
// ContentView.swift
// Landmarks
//
//
//アプリView用のコード
//マルチプラットフォームのAppテンプレートを利用している。
//iPhoneの作業で記載してきた。
//ということで他のプラットフォームを確認する→iPad
//SwiftUIはナビゲーションViewを分割Veiwに変更する
//ナビViewでサンドイッチの選択がない場合は、何も表示されない
//目標:サンドイッチのListを変更可能なものにする。
//編集サポートを追加する
import SwiftUI
struct ContentView: View {
//現在サンドイッチのデータモデルは固定値。
//なので、データモデルを更新してサンドイッチを含むルートストアオブジェクトを作成。
//時間の経過とともに変更されるようにする。
//ストアとは店ではなく、データが蓄積されたもののこと。
var sandwiches:[Sandwich] = []
var body: some View {
NavigationView{
List{ //データ駆動型
ForEach(sandwiches) { sandwich in //静的要素
SandwichCell(sandwich: sandwich)
}
HStack {
Spacer()//レイアウト要素
Text("\(sandwiches.count) Sandwitches")
.foregroundColor(.secondary)
Spacer()
}
}.navigationTitle("Sandwiches")
//分割View用に追加する(iPhoneでは自動的に削除される)
Text("Select a sandwich")
.font(.largeTitle)
}
}
}
//プレビューを表示する
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(sandwiches: testData)
}
}
struct SandwichCell: View {
var sandwich: Sandwich
var body: some View {
NavigationLink(destination:SandwichDetail(sandwich: sandwich)){
HStack{
Image(sandwich.thumbnailName)
.resizable()
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
VStack(alignment: .leading) { //セルの扱いになる。()内はViewの設定を変更している
Text(sandwich.name)
Text("\(sandwich.ingredientCount)ingredients")
//modifireというメソッドでViewの外観や動作をカスタマイズするのに使用する
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
}
}
//データモデルとは
現実世界の対象をデータ集合で表現しないと情報システムでは取り扱うことができない。
そのために、現実世界の対象を表す情報を抽象化して一定の構造や形式で記述したもの。
データモデルを作成することをデータモデリングという。
→なので今回でいうと、サンドイッチの種類をまとめたデータをもう少し現実的なデータにするよってことね。
初心者プログラミング日記
アプリ開発をしようと思い立って気づくと1年以上が過ぎていた。
SwiftUIでToDoアプリを作ろうとして挫折し、Unity C#で2DRPGを作ろうとして、
できそうな気はしているけど寄り道したいという今。
Unityで見えた世界もあったから、今、SwiftUIに戻ったらどんな景色が見えるか
見てみたい好奇心に負けて、何か1度は作品を完成させないと途中で辞めてしまうと、
いろんな記事で書くけれど、寄り道しようとしているところです。
プログラミングって楽しいよね。
何が楽しいって、こうやって動くだろうと思って動かなくて、
問題を突きつけられたのを、悩んで解決した時の爽快感。
ゲームやってるのと同じ感覚ではまってしまう。
探求型のパズルゲームって感じかな。