Simultaneous gestures のバグ

2021年1月26日

Simultaneous gestures を使っていてどうしても解決出来ないバグっぽいのがありました、お気をつけ下さい。

Simultaneous gesturesでRotationGesture と MagnificationGesture 同時使用

以下の様に Simultaneous gesture で 1 つの View に RotationGesture と MagnificationGesture を両方付与する事ができます。

struct TmpView10: View {
    
    @State private var lastMagnify: CGFloat = 1
    @State private var lastAngle: Angle = .degrees(.zero)
    @GestureState private var magnification: (active: Bool, factor: CGFloat) = (active: false, CGFloat(1))
    @GestureState private var angle: Angle = .degrees(.zero)

    
    var rotateGesture: some Gesture {
        let rotate = RotationGesture()
            .updating($angle) { (newAngle, gestureState, _) in
                gestureState = newAngle
            }
            .onEnded { angle in
                lastAngle += angle
            }
    
        return rotate
    }
    
    var magnifyGesture: some Gesture {

        
        let magnify = MagnificationGesture()
            .updating($magnification) { (value, gestureState, _) in
                gestureState.factor = value
                
                let delta = value / lastMagnify
                if abs(1 - delta) > 0.3 {
                    gestureState.active = true
                }
            }
            .onEnded { value in
                lastMagnify *= value
            }
        return magnify
    }

    var body: some View {
        
        Image(systemName: "suit.diamond")
            .resizable()
            .rotationEffect((lastAngle + angle))
            .scaleEffect(magnification.active ? (magnification.factor * lastMagnify) : lastMagnify)
            .gesture(rotateGesture)
            .simultaneousGesture(magnifyGesture)
           
    }

}

これで回転と拡大両方同時にできるようになったのですが、実はこれだと何故かピンチイン、アウトで拡大のみした時にその後拡大も回転も、両方ともジェスチャーが使えなくなります。。

分かりやすくするためこの様に minimumAngleDelta を使って RotationGesture が発火するまでの余裕を持たせて先に MagnificationGesture だけが動きやすくなる様にするとより顕著にこの事象が現れます。

 let rotate = RotationGesture(minimumAngleDelta: Angle(degrees: 10.0))

また、回転のジェスチャーのみを行った場合はその後拡大のジェスチャーだけが動かなくなります。以下の様にminimumScaleDelta を付与してから確認すると再現しやすくなります。

let magnify = MagnificationGesture(minimumScaleDelta:0.5)

SwiftUI 徹底入門 [ 金田 浩明 ]

価格:3,278円
(2020/11/18 22:49時点)
感想(0件)

一応の解決策。。。

一応ですが、以下の様に tap や drag など別のジェスチャーを入れるとまた正しく動き出します。しかしながらこれでは gesture が効かなくなったら tap したり drag したりと元々意図した動きとは変わってしまいます。ただこれでは拡大ジェスチャーが無効になった場合は元には戻りませんでした。。

        Image(systemName: "suit.diamond")
            .resizable()
            .rotationEffect((lastAngle + angle))
            .scaleEffect(magnification.active ? (magnification.factor * lastMagnify) : lastMagnify)
            .onTapGesture {}
            .gesture(rotateGesture)
            .simultaneousGesture(magnifyGesture)

正直理由は分からずで、明らかなバグな気がするのですが、、、

正しい解決方法をご存知の方は是非コメント等で教えて下さい !!

詳細!SwiftUI iPhoneアプリ開発入門ノート iOS 13 Xcode 11対応【電子書籍】[ 大重美幸 ]

価格:2,970円
(2020/11/18 22:52時点)
感想(0件)

SwiftUIではじめるiPhoneアプリプログラミング入門【電子書籍】[ 大津真 ]

価格:2,948円
(2021/1/24 23:24時点)
感想(0件)