SwiftUIでお絵かきアプリ
SwiftUIでお絵かきアプリを作りました。
指をなぞると線がかける機能があります。
https://github.com/SatoTakeshiX/EditorApp
ドラッグイベント
画面のドラッグイベントはView
の.gesture()
メソッドにDragGesture
インスタンスを引数にわたすと取得できます。DragGesture
のonChanged
メソッドでドラッグ中、onEnded
メソッドでドラッグ終了を検知できます。
.gesture(
DragGesture()
.onChanged({ (value) in})
.onEnded({ (value) in})
)
どちらもクロージャーでイベントのValueを取得できます。メンバー変数は次の通り。
- location: CGPoint, イベントの位置座標
- startLocation: CGPoint, イベントが始まったときの位置座標
線の引き方
線を引く方法はPath
を使います。クロージャーのpathに座標ポイントを渡すと線を引けます。
stroke
メソッドで色と線の幅を設定します。
Path { path in
path.addLines(self.points)//線を引くポイントの配列をパラメーターとして渡す
}
.stroke(self.tmpDrawPoints.color, lineWidth: 10)//
ドラッグ座標の扱い
今回線の色は赤と消しゴム(背景と同じ色指定で消えたようにみせる)の2つを用意しました。
ボタンで色の切り替えができるようにします。
VStack(spacing: 10) {
Button(action: {
self.selectedColor = .red
}) { Text("赤")
}
Button(action: {
self.selectedColor = .clear
}) { Text("消しゴム")
}
}
.frame(minWidth: 0.0, maxWidth: CGFloat.infinity)
.background(Color.gray)
ドラッグした場合の位置座標と色を保持するためにDrawPoints
という型を定義します。
struct DrawPoints: Identifiable {
var points: [CGPoint]
var color: Color
var id = UUID()
}
DrawPoints
をもとにViewを描画するDrawPathView
を定義します。
ZStack
とForEach
を組み合わせてDrawPoints
ごとにPathを作ります。
struct DrawPathView: View {
var drawPointsArray: [DrawPoints]
init(drawPointsArray: [DrawPoints]) {
self.drawPointsArray = drawPointsArray
}
var body: some View {
ZStack {
ForEach(drawPointsArray) { data in
Path { path in
path.addLines(data.points)
}
.stroke(data.color, lineWidth: 10)
}
}
}
}
お絵かきアプリ
今回のお絵かきアプリのViewをOverlayView
とします。プロパティを@State
で定義しておきます。
struct OverlayView: View {
@State var tmpDrawPoints: DrawPoints = DrawPoints(points: [], color: .red)
@State var endedDrawPoints: [DrawPoints] = []
@State var startPoint: CGPoint = CGPoint.zero
@State var selectedColor: DrawType = .red
var body: some View {}
キャンバスとなるViewをRectangle
で作ります。
.overlay
でDrawPathView
を作りドラッグした際のendedDrawPoints
を渡します。
またendedDrawPoints
だけだとドラッグが終了しないとPathの描画がされないので描画中に更新されるtmpDrawPoints
も利用してPathを描画しておきます。
Rectangle()
.foregroundColor(Color.white)
.frame(width: 300, height: 300, alignment: .center)
.overlay(
DrawPathView(drawPointsArray: endedDrawPoints)
.overlay(
// ドラッグ中の描画。指を離したらここの描画は消えるがDrawPathViewが上書きするので見た目は問題ない
Path { path in
path.addLines(self.tmpDrawPoints.points)
}
.stroke(self.tmpDrawPoints.color, lineWidth: 10)
)
)
.gesture(
DragGesture()
.onChanged({ (value) in
// ドラッグごとのイベントのみを更新する
if self.startPoint != value.startLocation {
self.tmpDrawPoints.points.append(value.location)
self.tmpDrawPoints.color = self.selectedColor.color
}
})
.onEnded({ (value) in
self.startPoint = value.startLocation
self.endedDrawPoints.append(self.tmpDrawPoints)
self.tmpDrawPoints = DrawPoints(points: [], color: self.selectedColor.color)
})
)
まとめ
簡単ですが、指でお絵かきアプリが作れました。
まとめます。
.gesture(DragGesture())
でドラッグイベントを取得するPath { path in }
で線を引く- ドラッグイベントごとに座標を保持する
- Viewに描画
宣伝
インプレスR&D社より、「1人でアプリを作る人を支えるSwiftUI開発レシピ」発売中です。
「SwiftUIでアプリを作る!」をコンセプトにSwiftUI自体の解説とそれを組み合わせた豊富なサンプルアプリでどんな風にアプリ実装すればいいかが理解できる本となっています。
iOS 14対応、Widgetの作成も一章まるまるハンズオンで解説しています。
SwiftUIを学びたい方、ぜひこちらのリンクをチェックしてください!