フォルダーを作成する
これまでの連載では、ひとつのアプリをひとつのファイル内で記述してきましたが、今回はそれぞれの画面をそれぞれのファイルに分けて作成します。
まずはXcodeのナビゲーターエリアの①LuckyLaughView.swift上で右クリックを押し、表示されたメニューから②New Folder from Selectionを押します。

新しくフォルダーが作成できました。③のフォルダー名にはLuckyLaughと入力します。

ルール画面を作成する
ファイルを新規作成する
ルール画面のコードを記述するためのファイルを新規作成します。新規ファイル作成手順でLuckyLaughRuleView.swiftファイルを追加します。次のようにLuckyLaughフォルダー内に新規作成したファイルを配置してください。ファイル作成時にフォルダー内にファイルがない場合は、ドラッグ & ドロップで移動することができます。

ルールを作成する
福笑いゲームのルールを理解してもらうために、ルール画面を作成します。今回は一般的なルールを記載していますが、アレンジ自由なので楽しめるルールを作成してみてください。
struct LuckyLaughRuleView: View {
var body: some View {
VStack(spacing: 32) {
Text("福笑い")
.font(.largeTitle)
.bold()
Text("福笑いは、目隠しをして顔の輪郭台紙に目や鼻などのパーツを置き、出来上がったユーモラスな顔をみんなで楽しむ日本の伝統的なゲームです。\nゲーム画面を開いて、目隠しをしてゲームを開始します。目が二つ、鼻、口のパーツが左上に置かれています。そのパーツを画面中央の輪郭内に移動させて顔を完成させましょう")
.padding()
}
}
}
改行に使用している\nの記号は、第4回で学んだ文字改行を行うための記号です。プレビュー結果も改行されたテキストが表示されています。

画像を使用する
すでにApple側が用意をしてくれているシステム画像の使用方法は学んでいますが、今回は開発者が用意した画像を使用する方法を説明します。
画像を追加する
まずは使用する画像をプロジェクトに追加します。
-
Xcodeのナビゲーターエリアにある
Assets.xcassetsを開きます。ここはプロジェクトで使用する画像や色などを管理する場所です。 -
サンプルファイルにある
画像_福笑いの中にある全ての画像ファイルを選択した状態でAssets.xcassets内のスペースにドラッグ&ドロップをします

画像ファイルのドラッグ&ドロップ後に、次のようにXcode上に反映されていれば画像の追加は完了です。

また、同じ画像を3サイズも用意した理由は、Appleのデバイスには、画面の解像度が異なるため、同じ画像でもデバイスに合わせてサイズを変える必要があります。
そのため、デバイスに合った画像サイズを用意することで、どのデバイスでも画像がきれいに表示されるようになります。
画像を配置し、リサイズする
LuckyLaughRuleView.swiftに戻り、コードを次のように変更して画像を配置します。画像を使用するには、Image(_ resource:)を使用します。
struct LuckyLaughRuleView: View {
var body: some View {
VStack(spacing: 32) {
Text("福笑い")
.font(.largeTitle)
.bold()
// ここを追加↓
Image(.luckyLaugh)
Text("福笑いは、目隠しをして顔の輪郭台紙に目や鼻などのパーツを置き、出来上がったユーモラスな顔をみんなで楽しむ日本の伝統的なゲームです。\nゲーム画面を開いて、目隠しをしてゲームを開始します。目が二つ、鼻、口のパーツが左上に置かれています。そのパーツを画面中央の輪郭内に移動させて顔を完成させましょう")
.padding()
}
}
}
これで追加した画像がプレビューにも反映されます。

少し画像が小さく感じたので、画像サイズを大きくします。Viewのサイズを変更するには、frameモディファイアを使用します。このモディファイアはImageだけでなく、サイズを変更したいViewに使用できます。
Image(.luckyLaugh)
// ここを追加↓
.frame(width: 160, height: 160)
プレビューを確認すると、frameでサイズを大きくしたはずですが、Imageはサイズを変更しても基本的には元のサイズで表示されてしまうため、画像の見た目の大きさは変更されていないように見えます。

画像の大きさにもframeの変更を反映するには、resizableモディファイアを使用します。
Image(.luckyLaugh)
// ここを追加↓
.resizable()
.frame(width: 160, height: 160)
これで画像が大きくなりました。

これでルール説明の画面は完成です。
ドラッグで移動できる画像を作成する
次にドラッグで移動できる機能を持った画像を作成します。新規ファイル作成手順で、DraggableImage.swiftを追加してください。また作成後のViewのコードも次のように変更します。
import SwiftUI
struct DraggableImage: View {
@State var position: CGPoint = .zero
let systemName: String
var body: some View {
Image(systemName: systemName)
.font(.system(size: 64))
.position(position)
.gesture(
DragGesture()
.onChanged { value in
position = value.location
}
)
}
}
#Preview {
DraggableImage(systemName: "eye")
}
LuckyLaughフォルダ内にDraggableImage.swiftが追加されて、次のようになっていれば問題ありません。

それでは、View内のコードについて説明していきます。
CGPointを理解する
State変数として定義されているpositionはCGPoint型ですが、CGPointは横方向(x)と縦方向(y)の2つの値を持ち、それによって平面上の位置を表す型です。
@State var position: CGPoint = .zero
また、.zeroは原点 (x: 0, y: 0)を示しており、iOSアプリの場合は左上が基準になっています。
そして、positionモディファイアを使用してViewの位置を指定した値に変更することができます。このImageの位置は初期値.zeroになっているため、最初の時点では画面の左上に配置されています。
Image(systemName: systemName)
.font(.system(size: 64))
// Viewを指定した位置に配置
.position(position)
SF Symbolsの画像はfontでサイズを変更する
画像のサイズを変更する方法として、resizableとframeモディファイアを使用する方法を学びましたが、SF Symbolsを使用するImage(systemName:)の場合は、.font(.system(size: ))でサイズを変更することができます。
Image(systemName: systemName)
.font(.system(size: 64))
ドラッグジェスチャーを追加する
Viewに特定のジェスチャーを追加するには、gestureモディファイアを使用します。そして、その中で検知したいジェスチャーを追加します。
今回追加しているDragGestureは、ユーザーが画面上でドラッグ動作を行った際に、その動作を認識し、アクションを実行するために使用されるジェスチャーです。
.gesture(
DragGesture()
.onChanged { value in
position = value.location
}
)
このonChangedを使用すると、ドラッグ中に位置や移動量などの値の変化を検知し、リアルタイムで更新される値を取得できます。今回は、ドラッグ中の位置情報value.locationを取得して、変数positionに代入しています。
実際にプレビュー上の目の画像をドラッグすると、移動できるので試してみてください。

