Circle Timer 만들기_3_User_Interation(SwiftUI, gesture, DragGesture)
Circle Timer 만들기_3_User_Interation(SwiftUI, gesture, DragGesture)
이제 타임 타이머와 마찬가지로 손가락을 이용해서 시간을 설정할 수 있는 기능을 넣겠습니다. 손가락으로 시간을 변경 하려면 사용자의 drag 제스쳐를 잡아낼 수 있어야 합니다.
사전에 만든 CircleShape를 화면에 붙여줍니다.
@State var endAngle: Double = 260
var body: some View {
CircleShape(endDegrees: self.$endAngle)
.foregroundColor(Color.red)
}
state와 binding의 개념은 다른 포스트에서 다루니 넘어가고 RxSwift BehviorRelay랑 비슷한 개념이라 보면 된다.
여기에 사용자 제스처를 잡기 위해서 viewModifier를 붙여 준다. 처음에 뭐를 붙여야 할지 모를 때 상단에 + 버튼을 누르고 찾아보면 도움이 많이 된다.
Drag Gesture 를 추가해본다.
CircleShape(endDegrees: self.$endAngle)
.foregroundColor(Color.red)
.gesture(DragGesture().onChanged { value in
/*
angle을 변경하는 동작
*/
}
이제 angle을 변경하는 동작을 살펴봐야 하는데, 요점은 우리가 선택한 CGPoint가 가운데 Center CGPoint에서 어느 각도에 위치해 있는지 계산하는 로직이 필요하다.
크게 고민 안하고 구글링했더니 바로 나왔다.
private func getAngle(center: CGPoint, target: CGPoint) -> CGFloat {
let originPoint = CGPoint(x: target.x - center.x,
y: target.y - center.y)
let bearingRadians = atan2f(Float(originPoint.y), Float(originPoint.x))
var bearingDegrees = bearingRadians * (180.0 / Float.pi)
bearingDegrees += 90
bearingDegrees = (bearingDegrees > 0.0
? bearingDegrees : (360.0 + bearingDegrees))
return CGFloat(bearingDegrees)
}
근데 이제 다음으로 Center 값을 알아야 한다. 어떻게 해야 할까? 이 CircleShape가 할당된 공간을 알아야 하는데 이럴 때 쓰는게 GeometryReader다.
GeometryReader가 할당되는 사이즈가 담긴 geometryProxy를 제공하기 때문에 사이즈를 알 수 있다.
GeometryReader { geometryProxy in
CircleShape(endDegrees: self.$endAngle)
.foregroundColor(Color.red)
.gesture(DragGesture().onChanged { value in
/*
화면 사이즈를 계산하고 Angle을 다시 그리는 과정
*/
},including: .gesture)
}
.frame(idealWidth: size.width,
maxWidth: size.width,
idealHeight: size.height,
maxHeight: size.height,
alignment: .center)
내부 angle을 그리는 과정은 다음과 같다.
let minSize = min(geometryProxy.size.width,
geometryProxy.size.height)
let size = CGSize(width: minSize, height: minSize)
let angle = self.getAngle(center: CGPoint(x: size.width / 2.0,
y: size.height / 2.0),
target: value.location)
print(angle)
// 각도계가 뒤집힌 형태여야 하니까 360에서 빼준다.
self.endAngle = 360.0 - Double(angle)