Search code examples
swiftuidraggesture

I try to create a Button with Drag Gesture like the bubble messenger of android


I created an Image with Drag gesture, but when I convert it to a Button, full screen become the button, so when I click to anywhere in the screen, the Button will be action

struct OwlFly: View {
    private var bround = UIScreen.main.bounds
    @State var isShow = false
    @State private var location = CGPoint(x: 60, y: 60)
    @GestureState private var startLocation: CGPoint? = nil
    var simpleDrag: some Gesture {
        DragGesture()
            .onChanged { value in
                var newLocation = startLocation ?? location
                newLocation.x += value.translation.width
                newLocation.y += value.translation.height
                self.location = newLocation
                self.location = value.location
            }
            .onEnded{ value in
                if(value.translation.width > bround.size.width/2) {
                    self.location.x = bround.size.width - 30
                }
                else {
                    self.location.x = 30
                }
            }
            .updating($startLocation) { (value, startLocation, transaction) in
                startLocation = startLocation ?? location
            }
    }
    var body: some View {
        Button(action: {
           self.isShow.toggle()
           if(isFly) {
                self.location.x = bround.width/2
           }
           else {
                self.location.x = 30
           }
        }) { // I convert the Image to a label of button
           Image("simpleDrag")
               .resizable()
               .aspectRatio(contentMode: .fit)
               .frame(width: 50)
               .animation(.easeInOut)
               .position(location)
               .gesture(simpleDrag)
            }
      }
}

That is my code


Solution

  • This is nice!

    The .position expands the view (and the button) to maximum size, that's why you can click everywhere.

    The easiest workaround is not using a Button, but making the image itself tappable – see code below.

    PS: You don't have to use @GestureState if you manage the dragging by yourself with onChanged and onEnded – you did a double job. I commented out everything you don't need ;)

    struct ContentView: View {
        
        private var bround = UIScreen.main.bounds
        @State var isShow = false
        @State private var location = CGPoint(x: 60, y: 60)
    //    @GestureState private var startLocation: CGPoint? = nil
        
        var simpleDrag: some Gesture {
            DragGesture()
                .onChanged { value in
    //                var newLocation = location
    //                newLocation.x += value.translation.width
    //                newLocation.y += value.translation.height
    //                self.location = newLocation
                    self.location = value.location
                }
                .onEnded{ value in
                    if(value.translation.width > bround.size.width/2) {
                        self.location.x = bround.size.width - 30
                    }
                    else {
                        self.location.x = 30
                    }
                }
    //            .updating($startLocation) { (value, startLocation, transaction) in
    //                startLocation = startLocation ?? location
    //            }
        }
        
        var body: some View {
            
            Image(systemName: "bubble.right.fill")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 50)
                .animation(.easeInOut, value: location)
                .position(location)
                .gesture(simpleDrag)
            
                .onTapGesture {
                    self.isShow.toggle()
                    if(isShow) {
                        self.location.x = bround.width/2
                    }
                    else {
                        self.location.x = 30
                    }
                }
        }
    }