スクリーンショット_2020-03-06_14.26.17

【Xcode】超初心者のためのSwiftUIチュートリアル11

手を骨折したため更新の間が空いてしまいました。
Apple公式のSwiftUIチュートリアルをプログラミング超初心者向けに優しく解説するシリーズ第11回。今回は「Drawing Paths and Shapes(パスとシェイプの描画)」の後半、セクション3・4を進めていきます。

第10回ではバッジ画像の背景となる六角形のグラデーション画像を作りました。今回の作業は次のような流れになります。

セクション3
・六角形を描いたBadge.swiftの名前を変更して、新たなBadge.swiftを作る
・新しいBadge.swiftに六角形の画像を呼び出して表示する
・新しいビューファイルに山の形のシンボルを作る
セクション4
・山のシンボルを回転させるための新しいビューファイルを作る
・Badge.swiftで背景になる六角形と山のシンボルを重ねる
・山のシンボルを回転させながら表示して、太陽のようなイメージにする

スクリーンショット 2020-02-08 10.52.06のコピー

Appleの公式チュートリアルはこちらを参照してください。日本語で閲覧したい場合は、自動翻訳機能のあるGoogleChromeなどのブラウザを使用するといいでしょう。

1.セクション3/Badge.swiftの名前を変える

まず、前に作った六角形の画像を部品のひとつとして扱うために、Badge.swiftの名前を変えます(rename)。struct名「Badge」の部分を2本指クリックしてRefactor > Rename... を選びます。

スクリーンショット 2020-02-06 17.43.41

2本指クリックは下図のようにします。出てこない場合はシステム環境設定でトラックパッドの設定を確認して「副ボタンのクリック」にあたる操作を行ってください。

スクリーンショット 2020-02-08 12.23.56

すると下のような画面になるので、「Badge」を「BadgeBackground」に変更します。

スクリーンショット 2020-02-06 17.44.22

これで同じ名前で紐づいているファイル名、struct名、プレビュー設定が一括で変更できます。

スクリーンショット 2020-02-08 12.53.13


2.新しいBadge.swiftを作る

名前を変更したら新たにBadge.swiftを作成します。手順は下の画像を参考にしてください。

スクリーンショット 2020-01-28 16.17.00

swiftUI Viewを選び、ファイル名をBadge.swiftと入力して作成します。

スクリーンショット 2020-01-28 16.17.17

このBadge.swiftがバッジ画像を描く新しいキャンバスになります。


3.別ファイルの六角形をBadge.swiftに表示する

Badge.swiftを下のように書き換えてプレビューを見ると、前回作った六角形の画像と同じように表示されます。

スクリーンショット 2020-02-08 14.04.38

Badge.swiftに画像を表示する際、前のようにキャンバスに直接図形を描くと表示が限定されます。一方、新しいBadge.swiftではキャンバスに別ファイルで用意した画像を呼び出して表示するので、さまざまに描画を変更することが可能です。

スクリーンショット 2020-02-08 14.11.53


4.新しいビューファイルにシンボルを描画する

次に、もう一つの画像ファイルを用意します。先ほどBadge.swiftを作ったのと同じ要領でBadgeSymbol.swiftというビューファイルを作ってください。作成したらbody内に山の形をしたシンボルの上部を描くコードを書きましょう。

スクリーンショット 2020-02-06 18.21.49

コードは以下の通りです。CGPointで設定した点を、順に線で結んで描画していきます。
画面の横幅に対する比率で頂点の位置を指定することで、デバイスの大きさが変わっても、その大きさに応じたサイズの画像を表示することができます。

GeometryReader { geometry in
    //シンボルの描画
    Path { path in
        let width = min(geometry.size.width, geometry.size.height)
        let height = width * 0.75 
        let spacing = width * 0.030
        let middle = width / 2
        let topWidth = 0.226 * width 
        let topHeight = 0.488 * height
        
        //シンボル上部       
        path.addLines([
            CGPoint(x: middle, y: spacing),
            CGPoint(x: middle - topWidth, y: topHeight - spacing),
            CGPoint(x: middle, y: topHeight / 2 + spacing),
            CGPoint(x: middle + topWidth, y: topHeight - spacing),
            CGPoint(x: middle, y: spacing),
        ])
    }
}


5.シンボルの下部を描画する

次はシンボルの下部分を描画します。

スクリーンショット 2020-02-06 18.30.47

こちらも上部の画像と同じように、x・yで指定した点を線で結びながら描画していきます。

//シンボル下部
path.move(to: CGPoint(x: middle, y: topHeight / 2 + spacing * 3)) //新しい描画を開始するポイント
path.addLines([
    CGPoint(x: middle - topWidth, y: topHeight + spacing),
    CGPoint(x: spacing, y: height - spacing),
    CGPoint(x: width - spacing, y: height - spacing),
    CGPoint(x: middle + topWidth, y: topHeight + spacing),
    CGPoint(x: middle, y: topHeight / 2 + spacing * 3),
])


6.シンボルを塗りつぶす

描画したシンボルに色をつけます。上部のsymbolColorで色を設定し、図形の下部に塗りつぶし指定します(.fill)。

スクリーンショット 2020-02-06 19.20.34

入力するコードは下の通り。

//シンボルの色指定
static let symbolColor = Color(red: 79.0 / 255, green: 79.0 / 255, blue: 191.0 / 255)
//塗りつぶし指定
.fill(Self.symbolColor)

これで山の形をしたシンボルができました。


7.セクション4/シンボルを回転させるビューを作る

次はシンボルのファイルとは別に、「回転させたシンボルを表示する」ための新たなビューファイルを作ります。ファイル名は「RotatedBadgeSymbol」にします。

スクリーンショット 2020-02-08 15.36.35

プレビュー設定にある「degrees」の数値を変えることで、シンボルの表示角度が変わります。いろいろな数値を入れて表示を確認してみましょう。

import SwiftUI

struct RotatedBadgeSymbol: View {
   
   let angle: Angle // Angleは角度設定に使う宣言
   
   var body: some View {
       BadgeSymbol() //バッジシンボルを呼び出す
           .padding(-60) //表示の大きさを指定
           .rotationEffect(angle, anchor: .bottom) //回転軸を下部に指定
   }
}

struct RotatedBadgeSymbol_Previews: PreviewProvider { //プレビュー設定
   static var previews: some View {
       RotatedBadgeSymbol(angle: .init(degrees: 5)) //5度回転したイメージを表示
   }
}


8.Badge.swiftにシンボルを重ねて表示する

バッジの素材となる画像ファイルが準備できたので、再びBadge.swiftを開きます。変数badgeSymbolsでRotatedBadgeSymbolの画像を呼び出し、すでにあるBadgeBackgroundと共にZStackで配置します。

スクリーンショット 2020-03-03 14.54.27


コードは下の通り。


import SwiftUI

struct Badge: View {
   
   var badgeSymbols: some View { //回転するシンボルを実体化
       RotatedBadgeSymbol(angle: .init(degrees: 0)) //回転角度0のシンボル
           .opacity(0.5) //画像透過率50%
   }
   
   var body: some View {
       
       ZStack {
           BadgeBackground() //バッジの背景画像
           
           self.badgeSymbols //回転するシンボル画像(背景画像の上に重なる)
                   
       }
   }
}

ZStackはアイテムを重ねて表示するときに使います。コードを書いた順番にアイテムを上に重ねていくので、BadgeBackgroundの上に透過率50%のRotatedBadgeSymbolが重なって表示されます。

スクリーンショット 2020-03-03 16.24.37

9.シンボルの大きさを調整する

このままだとシンボルが大きすぎるので、サイズを調整します。「self.badgeSymbols」の部分を下記のように書き換えましょう。command⌘+クリックを使ってGroupで囲んでから書き換えると楽です。

GeometryReader { geometry in //親ビューをもとに相対的に座標空間の値を返す
    self.badgeSymbols //回転するシンボル画像
        //大きさを縮小
        .scaleEffect(1.0 / 4.0, anchor: .top)
        //画像の配置を指定
        .position(x: geometry.size.width / 2.0, y: (3.0 / 4.0) * geometry.size.height)
}

するとサイズが縮小されて、このような表示になります。

スクリーンショット 2020-03-03 22.54.02


10.シンボルを回転させて表示する

いよいよシンボルを回転させます。 表示するシンボルの数をrotationCountで規定し、ForEach文を使って表示するシンボルの回転角度を求めます。コードは下の通りです。

static let rotationCount = 8 //表示するシンボルの数

var badgeSymbols: some View {
       ForEach(0..<Badge.rotationCount) { i in //0〜7までの数を代入して角度を決める
           RotatedBadgeSymbol(
               angle: .degrees(Double(i) / Double(Badge.rotationCount)) * 360.0
           )
       }
       .opacity(0.5) //透過率
   }

この段階で、ビューでは下図のように表示されます。iに0〜7が代入されて算出した角度で回転します。
これでiが1の時は角度(angle)が1/8×360=45°、iが2なら2/8×360=90°...となるわけです。

スクリーンショット 2020-03-03 23.32.43

プレビューの青い長方形は、1/4の大きさに縮小されたRotatedBadgeSymbolを示しています。同ファイル内で規定された通り、画面下部を軸にして回転してるわけです(下のコード参照)。

スクリーンショット 2020-03-04 1.40.42

さらに下図の部分に「.scaledToFit()」を追記すると、ZStack内の2つの画像BadgeBackgroundとRotatedBadgeSymbolは、描画のアスペクト比を維持しながらZStackと同じ縦横比になります。

RotatedBadgeSymbolは底部の余白がなくなることで、冒頭に示したような太陽に似た形の回転図に変化します。

スクリーンショット 2020-03-04 1.55.08

これでバッジの図案が完成しました。

スクリーンショット 2020-03-04 2.40.09


次回から「Animating Views and Transitions(ビューとトランジションのアニメーション化)」に入ります。

関連記事は下のマガジンからご覧ください。



この記事が気に入ったらサポートをしてみませんか?