SwiftUI 學習Gesture - 縮放手勢(MagnificationGesture)
xcode 13.4.1, swift 5.5, iOS 15.4
2022-08-23
Gesture是使用者與App交互的主要途徑,包括點按(Tap)、長按手勢(Long Press)、拖曳手勢(Drag)、縮放手勢(MagnificationGesture)、旋轉手勢(RotationGesture),縮放手勢(MagnificationGesture)也是很常用的手勢,在一些畫畫的App中很常用。
1. 以下程式使用了縮放手勢(MagnificationGesture)來做一個縮放View的效果,originalScale代表現在縮放的比例,而scale則是在使用縮放手勢期間的縮放比例,實作如下。
import SwiftUI
struct GestureExample : View {
@State private var originalScale = 1.0
@State private var scale = 1.0
var body: some View {
VStack {
Circle()
.frame(width: 50)
.foregroundColor(.black.opacity(0.8))
.overlay(
Image(systemName: "trash")
.resizable()
.scaledToFit()
.foregroundColor(.green)
.scaleEffect(0.7)
)
}
.scaleEffect(originalScale * scale)
.gesture(
MagnificationGesture()
.onChanged({ v in
scale = v
})
.onEnded({ v in
originalScale *= scale
scale = 1.0
})
)
}
}
2. 以上程式使用了縮放手勢(MagnificationGesture)的onChanged來跟蹤用縮放手勢期間的縮放比例,另一種可以使用updating方法來幫助跟蹤用縮放手勢期間的縮放比例,但scale變量就要從@State改用@GestureState,而且使用這種方法不需要在手勢結束時onEnded把scale改回初始值,因為MagnificationGesture會幫忙做這個工作,程式實作如下。
import SwiftUI
struct GestureExample : View {
@State private var originalScale = 1.0
@GestureState private var scale = 1.0
var body: some View {
VStack {
Circle()
.frame(width: 50)
.foregroundColor(.black.opacity(0.8))
.overlay(
Image(systemName: "trash")
.resizable()
.scaledToFit()
.foregroundColor(.green)
.scaleEffect(0.7)
)
}
.scaleEffect(originalScale * scale)
.gesture(
MagnificationGesture()
.updating($scale, body: { currentState, state, transaction in
state = currentState
})
.onEnded({ value in
originalScale *= value
})
)
}
}
縮放手勢使用MagnificationGesture 的 updating 方法,在拖動整個期間會不斷的被呼叫,並且接收三個參數: currentState、state 與 transaction :
currentState 參數是手勢當前的狀態。這個值會依照手勢而有所不同,不過針對MagnificationGesture,currentState會包含有當前最新的縮放比例。
state 參數實際上是一個 in-out 參數,可以更新你在updating 方法的binding的參數: scale 屬性的值。在以下的程式中,我們設定 state 的值為 currentState的當前位置 ,然後通過SwiftUI的Binding又把state的值更新scale的值,從而用來控制View的scaleEffect縮放比例。
transaction 參數是gesture的上下文環境,暫時用不到。