The Util Designer
SwiftUI 學習Gesture - 長按手勢(Long Press)
xcode 13.4.1, swift 5.5, iOS 15.4
2022-08-23
Gesture是使用者與App交互的主要途徑,包括點按(Tap)、長按手勢(Long Press)、拖曳手勢(Drag)、縮放手勢(MagnificationGesture)、旋轉手勢(RotationGesture),有時為了避免使用者不小心按到,而要求使用長按才來觸發事件,就可以用手勢(Long Press)。
1. SwiftUI 已把長按手勢(Long Press)做成內建的Gesture,很方便很容易就可以在App加入長按手勢的功能,跟其他Gesture一樣,也是在View中的gesture指定LongPressGesture,並在LongPressGesture傳入參數minimumDuration來指定長按多長時間才觸發長按手勢,以下指定長按1.0秒後才觸發長按手勢,實作如下。

import SwiftUI

struct GestureExample : View {
    @State private var isLongPressed = false
    var body: some View {
        Image(systemName: "ladybug.fill")
            .foregroundColor(.green)
            .scaleEffect(isLongPressed ? 0.5 : 1.0)
            .font(.system(size: 200))
            .gesture(
                LongPressGesture(minimumDuration: 1.0)
                    .onEnded({ value in
                        isLongPressed.toggle()
                    })
            )

    }
}
2. 從上面長按一秒後,圖片立即變大,再長按一秒後,圖片又立即變大,其實還可以指定控制圖片大小的變量為animation,就可以做到以動畫來過渡圖片的變大和變小,實作如下。
import SwiftUI

struct GestureExample : View {
    @State private var isLongPressed = false
    var body: some View {
        Image(systemName: "ladybug.fill")
            .foregroundColor(.green)
            .scaleEffect(isLongPressed ? 0.5 : 1.0)
            .font(.system(size: 200))
            .animation(.easeIn(duration: 1.0), value: isLongPressed)
            .gesture(
                LongPressGesture(minimumDuration: 1.0)
                    .onEnded({ value in
                        isLongPressed.toggle()
                    })
            )

    }
}
3. 現在在手指按下時,頁面沒有作出任何反饋,為了讓使用者知道自己已按下了手指,我們把圖片變得透明一點。
我們使用LongPressGesture 的 updating 方法。在長按手勢執行期間,這個方法將會被呼叫,並且接收三個參數: currentState、state 與 transaction :
currentState 參數是手勢當前的狀態。這個值會依照手勢而有所不同,不過針對長按手勢,true 值表示偵測到點按事件。
state 參數實際上是一個 in-out 參數,可以更新你在updating 方法的binding的參數: isTouchDown 屬性的值。在以下的程式中,我們設定 state 的值為 currentState ,然後通過SwiftUI的Binding又把state的值更新isTouchDown的值,從而用來控制View的opacity狀態。
transaction 參數是gesture的上下文環境,暫時用不到。
import SwiftUI

struct GestureExample : View {
    @State private var isLongPressed = false
    @GestureState private var isTouchDown = false
    var body: some View {
        Image(systemName: "ladybug.fill")
            .foregroundColor(.green)
            .opacity(isTouchDown ? 0.4 : 1.0)
            .scaleEffect(isLongPressed ? 0.5 : 1.0)
            .font(.system(size: 200))
            .animation(.easeIn(duration: 1.0), value: isLongPressed)
            .gesture(
                LongPressGesture(minimumDuration: 1.0)
                    .updating($isTouchDown, body: { currentState, state, transaction in
                        state = currentState
                    })
                    .onEnded({ value in
                        isLongPressed.toggle()
                    })
            )

    }
}