DragGestureで回転させる
Published by @SoNiceInfo at 6/24/2020
DragGesture
は一本指で行う動作で移動した位置や距離の座標しか取得できません。atan2を使った回転を扱うのに必要な回転角度の求め方と実装方法をを紹介します。
回転角度の計算方法
DragGesture
で回転を実装する前に回転角度の計算方法を理解する必要があります。DragGesture
では回転角度を自分で計算する必要があります。DragGesture
で取得できるlocation:CGPoint
から回転角度を求めるのに必要な考え方をまとめた図です。
青がDragGesture
の座標系で、オレンジが回転体の座標系で回転角度θを求めるのに必要です。DragGesture
のlocation:CGPoint
と回転体の直径self.length
を使うと点Pは(v.location.x - self.length / 2, self.length / 2 - v.location.y)
となります。
そして回転角度はθ=arctan(v.location.x - self.length / 2, self.length / 2 - v.location.y) * 180 * π (θ < 0 ? θ += 360)となります。
DragGesture
による実装 part1
物体の回転角度 = ジェスチャーの回転角度
物体を回転させるたびに角度がリセットされる実装方法です。atan2
(アークタンジェント)を使って回転角度θを求めてrotationEffect
に渡しています。
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
@State private var angle: CGFloat = 0
@State private var length : CGFloat = 400
var body: some View {
Image("ice")
.resizable()
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
.frame(width: length, height: length)
.rotationEffect(.degrees(Double(self.angle)))
.gesture(DragGesture()
.onChanged{ v in
self.angle = atan2(v.location.x - self.length / 2, self.length / 2 - v.location.y) * 180 / .pi
if (self.angle < 0) { self.angle += 360 }
}
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
DragGesture
による実装 part2
物体の回転角度 += ジェスチャーの回転角度
物体を回転させるたびに回転角度をプラスしていく実装方法も紹介します。atan2
(アークタンジェント)を使ってスタートポイントの回転角度と移動中のポイントの回転角度差θを求めます。
回転が終わったらlastAngle
に最終的な角度を保存しておき、次の回転の回転角度差とプラスしてあげます。
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
@State private var angle: CGFloat = 0
@State private var lastAngle: CGFloat = 0
@State private var length : CGFloat = 400
var body: some View {
Image("ice")
.resizable()
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
.frame(width: length, height: length)
.rotationEffect(.degrees(Double(self.angle)))
.gesture(DragGesture()
.onChanged{ v in
var theta = (atan2(v.location.x - self.length / 2, self.length / 2 - v.location.y) - atan2(v.startLocation.x - self.length / 2, self.length / 2 - v.startLocation.y)) * 180 / .pi
if (theta < 0) { theta += 360 }
self.angle = theta + self.lastAngle
}
.onEnded { v in
self.lastAngle = self.angle
}
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
参考
Gestures | Apple Developer Documentationgeometry - calculating angle between two points on edge of circle Swift SpriteKit - Stack Overflow