SwiftUIチュートリアルのDrawing Paths and Shapesの座標計算部分を解読する

samekard
Swift・iOSコラム
Dec 14, 2022

この公式SwiftUIチュートリアルの図形描画は難解なので、分解してひとつひとつ見ていきます。

元ネタの問題の部分

この下の方の3.0 / 4.0の根拠がわかりにくいですな。

それではやっていきます。

Paddingがマイナスの部分を消す

まず、説明の邪魔になるものを省きます。上で出したのとは別の場所でPaddingがマイナスになっている部分があります。これは領域からはみ出てしまい説明の邪魔になるので消します。

いろいろ消してシンプルに

次に初期状態を作ります。いろいろ消してシンプルな状態にします。ただし背景の赤だけ追加。

  • ForEach の回数を1回にします
  • RotatedBadgeSymbol に背景色の赤を付けます
  • ZStack.scaledToFit() を消します
  • ZStack の中の BadgeBackground() を消します
  • badgeSymbols のmodifierを全部消します

背景赤に山のイラストが描かれているだけになりました。ここから本格的にスタートです。

ZStackに.scaledToFit()追加

ZStack.scaledToFit() を有効にします。これはアスペクト比を1:1にする機能があります。 ZStack のアスペクト比が1:1になりました。Y方向のセンタリングもされました。中にある RotatedBadgeSymbol の領域もそれに従って変化して、赤色の正方形が真ん中に来ました。

回転ループを2回に

ForEach のループを2回にしました。回転する RotatedBadgeSymbol には赤背景がついていますが、2回とも背景の赤が塗られる部分が同じことがポイントです。斜めになった四角い赤は現れません。

繰り返しを8回にする

8回繰り返したので赤がかなり濃くなって来ました。回転指令を出しても、背景モディファイアの色塗りは元の位置に対して適用されました。

この後に適用されるモディファイアはこの赤エリアに対して計算をします。

スケール1/4を適用する

badgeSymbols に1/4に縮小するモディファイアを適用します。軸は .top です。ここには8個のViewがありますが、すべて赤色のエリアに対して1/4が適用されます。

8個の山をひとつにまとめた領域に対して1/4の操作がされているようにも解釈できますが、試しに繰り返しを3回にすると次のようになり、赤色のエリアに対して1/4の操作の計算がされていることがわかります。(3つの山をまとめた領域に対して縮小操作がされればもう少し右にくるはず)

背景を緑に

1/4適用後に、背景を緑にするモディファイアを付けます。このとき緑は1/4適用前のエリアに塗られています。

この先の操作もこの緑のエリアに対して行われます。

中心を移動

上のスクリーンショットでは家紋のY中心は ZStack (緑とちょうど同じ)の上から25%の位置にあります。これを50%の位置にしたいです。

それには badgeSymbols への .position 操作を行います。これは緑のエリアに対して適用されます。Y中心がもともと ZStack に対して50%の位置にあります。これを75%にします。つまり高さに3/4掛けた値を設定します。

ZStack の上から1/2だった中心を3/4にしました。緑色もずれました。

六角形の背景を融合

BadgeBackground() を有効にして六角形のピンクの背景を表示すると家紋と背景がきちんとセンタリングされています。

背景色を削除

背景色を削除して元のコードと(Padding以外は)同じ状態にしましょう。

終わりに

間違っていたら指摘をお願いします。

回転や拡大/縮小の操作をしても情報は元の位置にあるという、まぼろしの見た目にうまく付き合っていきましょう。

記事を書いてから気が付いたのですが、内側から(つまりモディファイア適用順に)解釈していくとややこしいだけで、外側から解釈するとすっきりする特徴があります。

現在SwiftUIチュートリアルを進めております。追加の記事があればまた書きます。

この記事は2022 アベントカレンダー SwiftUIへの投稿でした。12/15日を担当しました。

検索用

Drawing paths and shapes

Drawing and animation

SwiftUI Tutorial

--

--

samekard
Swift・iOSコラム

iOSアプリをいろいろ作りました。英語と中国語を勉強中。