The Util Designer
SwiftUI 學習Gesture - 旋轉手勢(RotationGesture)
xcode 13.4.1, swift 5.5, iOS 15.4
2022-08-23
Gesture是使用者與App交互的主要途徑,包括點按(Tap)、長按手勢(Long Press)、拖曳手勢(Drag)、縮放手勢(MagnificationGesture)、旋轉手勢(RotationGesture),旋轉手勢(RotationGesture)也是很常用的手勢,在一些畫畫的App中很常用。
1. 以下程式使用了旋轉手勢(RotationGesture)來做一個旋轉手勢的效果,originalAngle代表現在旋轉角度,而angle則是在使用旋轉手勢期間的所增加或減少的角度,實作如下。
import SwiftUI

struct GestureExample : View {
    @State private var originalAngle = Angle.zero
    @State private var angle = Angle.zero
    var body: some View {
        VStack {
            Circle()
                .frame(width: 200)
                .foregroundColor(.black.opacity(0.8))
                .overlay(
                    Image(systemName: "trash")
                        .resizable()
                        .scaledToFit()
                        .foregroundColor(.green)
                        .scaleEffect(0.7)
                )
        }
        .rotationEffect(originalAngle + angle)
        .gesture(
            RotationGesture()
                .onChanged({ value in
                    angle = value
                })
                .onEnded({ value in
                    originalAngle += value
                    angle = .zero
                })
        )
    }
}
2. 以上程式使用了旋轉手勢(RotationGesture)的onChanged來跟蹤用旋轉手勢期間所旋轉的角度,另一種可以使用updating方法來幫助跟蹤用旋轉的角度,但angle變量就要從@State改用@GestureState,而且使用這種方法不需要在手勢結束時onEnded把angle改回初始值,因為RotationGesture會幫忙做這個工作,程式實作如下。
import SwiftUI
struct GestureExample1 : View {
    @State private var originalAngle = Angle.zero
    @GestureState private var angle = Angle.zero
    var body: some View {
        VStack {
            Circle()
                .frame(width: 200)
                .foregroundColor(.black.opacity(0.8))
                .overlay(
                    Image(systemName: "trash")
                        .resizable()
                        .scaledToFit()
                        .foregroundColor(.green)
                        .scaleEffect(0.7)
                )
        }
        .rotationEffect(originalAngle + angle)
        .gesture(
            RotationGesture()
                .updating($angle, body: { currentState, state, transaction in
                    state = currentState
                })
                .onEnded({ value in
                    originalAngle += value
                })
        )
    }
}
旋轉手勢使用RotationGesture 的 updating 方法,在拖動整個期間會不斷的被呼叫,並且接收三個參數: currentState、state 與 transaction :
currentState 參數是手勢當前的狀態。這個值會依照手勢而有所不同,不過針對RotationGesture,currentState會包含有當前最新的旋轉角度。
state 參數實際上是一個 in-out 參數,可以更新你在updating 方法的binding的參數: angle 屬性的值。在以下的程式中,我們設定 state 的值為 currentState的當前位置 ,然後通過SwiftUI的Binding又把state的值更新angle的值,從而用來控制View的rotationEffect的旋轉角度。
transaction 參數是gesture的上下文環境,暫時用不到。