The Util Designer
SwiftUI 學習Gesture - 同時使用旋轉手勢(RotationGesture)與縮放手勢(MagnificationGesture)
xcode 13.4.1, swift 5.5, iOS 15.4
2022-08-23
在SwiftUI所提供的Gesture中,縮放手勢(MagnificationGesture)和旋轉手勢(RotationGesture)通常會一起使用,特別是在一些畫畫的App更是經常見到。
1. 以下程式使用了旋轉手勢(RotationGesture)來做一個旋轉手勢的效果,originalAngle代表現在旋轉角度,而angle則是在使用旋轉手勢期間的所增加或減少的角度,實作如下。
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
                })
        )
    }
}
2. 然後使用Gesture的simultaneously方法疊加縮放手勢(MagnificationGesture),originalScale代表現在縮放的比例,而scale則是在使用縮放手勢期間的縮放比例,就可以在同一時間做旋轉又進行縮手勢,放實作如下。
import SwiftUI

struct GestureExample : View {
    @State private var originalScale = 1.0
    @GestureState private var scale = 1.0

    @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)
                )
        }
        .scaleEffect(originalScale * scale)
        .rotationEffect(originalAngle + angle)
        .gesture(
            RotationGesture()
                .updating($angle, body: { currentState, state, transaction in
                    state = currentState
                })
                .onEnded({ value in
                    originalAngle += value
                })
                .simultaneously(with:
                        MagnificationGesture()
                            .updating($scale, body: { currentState, state, transaction in
                                state = currentState
                            })
                            .onEnded({ value in
                                originalScale *= value
                            })
                )
        )

    }
}