見出し画像

SwiftUI Tutorials - Drawing Paths and Shapes

最終的にはリスト内にある場所に行った時にバッジをつけることができるようにします。このチューリアルではそのバッジを作ります。

全体の流れですが、まず、六角形の座標を決め、その背景を作ります。その六角形の中にシンボルとなる形を作り上げ、色を付けて出来上がりです。

Create Drawing Data for a Badge View

新しくHexagonParameters.swiftファイルを追加して構造体"HexagonParameters"を作りデータ構造を定義しておきます。。

六角形を作っていくので6辺の区切り、各辺の位置を決めます。左上の座標が

(x, y) = (0, 0) 

となり、"X"は右方面が"正"、"y"は下方面が"正"となります。

  struct Segment {
       let line: CGPoint
       let curve: CGPoint
       let control: CGPoint
   }
   
   
   static let adjustment: CGFloat = 0.085
   
   static let segments = [
       Segment(
           line:    CGPoint(x: 0.60, y: 0.05),
           curve:   CGPoint(x: 0.40, y: 0.05),
           control: CGPoint(x: 0.50, y: 0.00)
       ),
       Segment(
           line:    CGPoint(x: 0.05, y: 0.20 + adjustment),
           curve:   CGPoint(x: 0.00, y: 0.30 + adjustment),
           control: CGPoint(x: 0.00, y: 0.25 + adjustment)
       ),
       Segment(
           line:    CGPoint(x: 0.00, y: 0.70 - adjustment),
           curve:   CGPoint(x: 0.05, y: 0.80 - adjustment),
           control: CGPoint(x: 0.00, y: 0.75 - adjustment)
       ),
       Segment(
           line:    CGPoint(x: 0.40, y: 0.95),
           curve:   CGPoint(x: 0.60, y: 0.95),
           control: CGPoint(x: 0.50, y: 1.00)
       ),
       Segment(
           line:    CGPoint(x: 0.95, y: 0.80 - adjustment),
           curve:   CGPoint(x: 1.00, y: 0.70 - adjustment),
           control: CGPoint(x: 1.00, y: 0.75 - adjustment)
       ),
       Segment(
           line:    CGPoint(x: 1.00, y: 0.30 + adjustment),
           curve:   CGPoint(x: 0.95, y: 0.20 + adjustment),
           control: CGPoint(x: 1.00, y: 0.25 + adjustment)
       )
   ]
}

六角形の形状を調整する調整値を設定しています。

static let adjustment: CGFloat = 0.085

Draw the Badge Background

実際の表示部分を作っていきます。新しいSwiftUIのファイルを作ります。

ここでPath()の使い方ですが

でわかりやすく解説されています。

続きです。

ファイル名をBadgeBackground.swiftとして構造体BadgeBackgroundを作ります。"Path()"を使って図形をつくり色を付けます。

var body: some View {
       Path { path in

       }
       .fill(Color.black)
 }

そして描画する範囲を決め、描画を開始する座標を指定します。

Path { path in
           var width: CGFloat = 100.0
           let height = width
           path.move(
               to: CGPoint(
                   x: width * 0.95,
                   y: height * 0.20
               )
           )
  }

ここでは範囲は100×100pxで座標が(x:100*0.95, y:100*0.2)としています。

次に先に決めている"segments"を使って線を描画します・

HexagonParameters.segments.forEach { segment in
               path.addLine(
                   to: CGPoint(
                       x: width * segment.line.x,
                       y: height * segment.line.y
                   )
               )
 }

ここでちょっと表示してみると六角形が変形しています。でも、

Don’t worry if your hexagon looks a little unusual; that’s because you’re ignoring the curved part of each segment at the shape’s corners. You’ll account for that next.

ということで湾曲部の調整が必要です。

Path { path in
           var width: CGFloat = 100.0
           let height = width
           path.move(
               to: CGPoint(
                   x: width * 0.95,
                   y: height * 0.20
               )
           )
  }
y: height * (0.20 + HexagonParameters.adjustment)

として数値を追加し、

path.addQuadCurve(
                   to: CGPoint(
                       x: width * segment.curve.x,
                       y: height * segment.curve.y
                   ),
                   control: CGPoint(
                       x: width * segment.control.x,
                       y: height * segment.control.y
                   )
               )

カーブを追加します。

そしてここで

 GeometryReader { geometry in
           Path { path in
               var width: CGFloat = min(geometry.size.width, geometry.size.height)
               let height = width
               path.move(
                   to: CGPoint(
                       x: width * 0.95,
                       y: height * (0.20 + HexagonParameters.adjustment)
                   )
               )
   }
GeometryReader

を使って実際の表示画面を取得して画面いっぱいの表示をするようにします。

次に

Path { path in
               var width: CGFloat = min(geometry.size.width, geometry.size.height)
               let height = width
               let xScale: CGFloat = 0.832
               let xOffset = (width * (1.0 - xScale)) / 2.0
               width *= xScale
               path.move(
                   to: CGPoint(
                       x: width * 0.95 + xOffset,
                       y: height * (0.20 + HexagonParameters.adjustment)
                   )
               )
               HexagonParameters.segments.forEach { segment in
                   path.addLine(
                       to: CGPoint(
                           x: width * segment.line.x + xOffset,
                           y: height * segment.line.y
                       )
                   )
                   path.addQuadCurve(
                       to: CGPoint(
                           x: width * segment.curve.x + xOffset,
                           y: height * segment.curve.y
                       ),
                       control: CGPoint(
                           x: width * segment.control.x + xOffset,
                           y: height * segment.control.y
                       )
                   )
               }
           }
let xScale: CGFloat = 0.832
let xOffset = (width * (1.0 - xScale)) / 2.0

をセットして、"x"のパラメータの部分に"xOffset"を当てて、中央に持っていきます。。

最後に図形の背景の色を決めていきます。

.fill(LinearGradient(
               gradient: Gradient(colors: [Self.gradientStart, Self.gradientEnd]),
               startPoint: UnitPoint(x: 0.5, y: 0),
               endPoint: UnitPoint(x: 0.5, y: 0.6)
           ))
 static let gradientStart = Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255)
   static let gradientEnd = Color(red: 239.0 / 255, green: 172.0 / 255, blue: 120.0 / 255)
}

六角形の座標を決め、その背景までできました。

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