简体   繁体   English

SwiftUI 拖动手势没有结束

[英]SwiftUI Drag gesture is not ending

I was trying to create a custom View with rotation effects in SwiftUI .我试图在SwiftUI中创建一个具有旋转效果的自定义视图。 Instead of using rotation gestures, I was trying to use the Drag Gesture to rotate the Parent by adding a separate view to the parent.我没有使用旋转手势,而是尝试使用拖动手势通过向父级添加单独的视图来旋转父级。 Dragging the child (The Blue Dot) would rotate its parent (ZStack).拖动子项(蓝点)将旋转其父项(ZStack)。 But I've faced difficulty while dragging the blue dot.但是我在拖动蓝点时遇到了困难。 The drag gesture is not ending.拖动手势没有结束。 Can you guys help me to find out what I did wrong?你们能帮我找出我做错了什么吗?

import SwiftUI

struct EditingHolder: View {

    /* For Rotation Circle Drag */
    @State private var currDragRect : CGSize = .zero
    @State private var prevDragRect : CGSize = .zero
    var rectRadius : CGFloat {
        let sum : CGFloat = 2*pow(150, 2)
        return sqrt(sum/4)
    }

    var dragRadius : CGFloat {
        let height = prevDragRect.height + currDragRect.height
        let width = prevDragRect.width + currDragRect.width
        let sum = pow(height, 2) + pow(width, 2)
        return sqrt(sum/4)
    }

    var rotateAngle : CGFloat{
        let angle = asin(dragRadius/rectRadius)
        print("🍄 Angle Produced = ", angle)
        return angle
    }

    var body: some View {
        /* **** Gestures **** */
        let rotateDrag = DragGesture()
            .onChanged({ value in
                print("🏵 Rotate Circle Drag Started ...")
                currDragRect = value.translation

            }).onEnded({ _ in
                print("🏵 Rotate Circle Drag Ended ✅")
                prevDragRect.height += currDragRect.height
                prevDragRect.width += currDragRect.width
                currDragRect = .zero
            })

        //************* Views *******************

        GeometryReader { geo in
            ZStack(alignment: .center) {
                Rectangle()
                    .padding()
                    .foregroundColor(Color.yellow)

                ///Rotate Circle `top`
                Circle()
                    .foregroundColor(Color.blue)
                    .frame(width: 20, height: 20)
                    .position(x: 150 - 3, y: 3)
                    .gesture(rotateDrag)

            }.frame(width:150, height: 150, alignment: .center)
                .border(.green, width: 3)
                .position(x: geo.size.width/2, y: geo.size.height/2)
                .rotationEffect(.radians(rotateAngle))

        }

        //************* Views *******************
    }
}

struct EditingHolder_Previews: PreviewProvider {
    static var previews: some View {
        EditingHolder()
    }
}

To provide high priority to a specific gesture there is a modifier called .highPriorityGesture() .要为特定手势提供高优先级,有一个名为.highPriorityGesture()的修饰符。 Have a look here for a better explanation How to use gestures in SwiftUI .看看这里以获得更好的解释如何在 SwiftUI 中使用手势

I've updated the angle calculations,我已经更新了角度计算,

    /* **** Gestures **** */
    let rotateDrag = DragGesture()
        .onChanged({ value in
            print("🏵 Rotate Circle Drag Started ...")
            
            let difY = center.y - value.location.y
            let difX = center.x - value.location.x
            
            //Initial Angle when the drag started..
            if deltaAngle == 0{
                deltaAngle = atan2(difY, difX)
            }else{
                angle = atan2(difY, difX) - deltaAngle
            }

        }).onEnded({ _ in
            print("🏵 Rotate Circle Drag Ended ✅")
            withAnimation {
                angle = 0
                deltaAngle = 0
            }
        })

    //************* Views *******************

Now to add .highPriorityGesture(rotateDrag) to ZStack .现在将.highPriorityGesture(rotateDrag)添加到ZStack

.onTapGesture() is added to get the center for angle calculation.添加.onTapGesture()以获取角度计算的center Tap on the view and then rotate by dragging the blue dot.点击视图,然后通过拖动蓝点进行旋转。 Here is the final implementation,这是最终的实现,

    struct EditingHolder: View {

    /* For Rotation Circle Drag */
    @State private var center : CGPoint = .zero
    @State private var angle : CGFloat = 0
    @State private var deltaAngle : CGFloat = 0

    var body: some View {
        /* **** Gestures **** */
        let rotateDrag = DragGesture()
            .onChanged({ value in
                print("🏵 Rotate Circle Drag Started ...")
                
                let difY = center.y - value.location.y
                let difX = center.x - value.location.x
                
                //Initial Angle when the drag started..
                if deltaAngle == 0{
                    deltaAngle = atan2(difY, difX)
                }else{
                    angle = atan2(difY, difX) - deltaAngle
                }

            }).onEnded({ _ in
                print("🏵 Rotate Circle Drag Ended ✅")
                withAnimation {
                    angle = 0
                    deltaAngle = 0
                }
            })

        //************* Views *******************

        GeometryReader { geo in
            ZStack(alignment: .center) {
                Rectangle()
                    .padding()
                    .foregroundColor(Color.yellow)

                ///Rotate Circle `top`
                Circle()
                    .foregroundColor(Color.blue)
                    .frame(width: 20, height: 20)
                    .position(x: 150 - 3, y: 3)
                    .gesture(rotateDrag)

            }.frame(width:150, height: 150, alignment: .center)
                .border(.green, width: 3)
                .position(x: geo.size.width/2, y: geo.size.height/2)
                .rotationEffect(Angle(radians: angle))
            /* You have make the gesture a high priority */
                .highPriorityGesture(rotateDrag)
                .onTapGesture {
                    print("☘️ Center assigned..")
                    center = CGPoint(x: geo.frame(in: .global).size.width/2, y: geo.frame(in: .global).size.height/2)
                    
                }

        }

        //************* Views *******************
    }
}

struct EditingHolder_Previews: PreviewProvider {
    static var previews: some View {
        EditingHolder()
    }
}

The sequence of drag gesture and rotation is important, otherwise SwiftUI looses context of the dragged view (which is changing by drag).拖动手势和旋转的顺序很重要,否则 SwiftUI 会丢失被拖动视图的上下文(通过拖动而变化)。

Also you don't need GeometryReader.你也不需要 GeometryReader。 Here is an example that works in regards to the dragging, the angle calculation needs some more work.这是一个关于拖动的例子,角度计算需要更多的工作。

struct ContentView: View {
    
    /* For Rotation Circle Drag */
    @State private var currDragRect : CGSize = .zero
    @State private var prevDragRect : CGSize = .zero
    let rectRadius : CGFloat = 75
    
    var dragRadius : CGFloat {
        let height = prevDragRect.height + currDragRect.height
        let width = prevDragRect.width + currDragRect.width
        let sum = pow(height, 2) + pow(width, 2)
        return sqrt(sum/4)
    }
    
    var rotateAngle : CGFloat{
        let x = min(1, max(-1, dragRadius/rectRadius)) // asin only defined in -1...1
        let angle = asin(x)
        print("🍄 Angle Produced = ", angle)
        return angle
    }
    
    var body: some View {
        
        /* **** Gestures **** */
        let rotateDrag = DragGesture()
            .onChanged { value in
                print("🏵 Rotate Circle Drag Started ...")
                currDragRect = value.translation
                
            }
            .onEnded { _ in
                print("🏵 Rotate Circle Drag Ended ✅")
                prevDragRect.height += currDragRect.height
                prevDragRect.width += currDragRect.width
                currDragRect = .zero
            }
        
        //************* Views *******************
        
        ZStack(alignment: .topTrailing) {
            Rectangle()
                .padding()
                .foregroundColor(Color.yellow)
                .border(.green, width: 3)
            
            ///Rotate Circle `top`
            Circle()
                .foregroundColor(Color.blue)
                .frame(width: 20, height: 20)
                .offset(x: 8, y: -8)
            
        }
        .rotationEffect(.radians(rotateAngle))  // rotation here
        .gesture(rotateDrag)                    // drag here
        .frame(width:150, height: 150, alignment: .center)
        
        //************* Views *******************
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM