我尝试创建一个带有拖动手势的按钮,就像 android 的气泡信使

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

我用拖动手势创建了一个图像,但是当我把它转换成一个按钮时,全屏变成了按钮,所以当我点击到屏幕上的任何地方时,按钮就会动作

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)
            }
      }
}

这是我的代码

这很好!

.position 将视图(和按钮)扩展到最大尺寸,这就是您可以在任何地方单击的原因。

最简单的解决方法是不使用按钮,而是使图像本身可点击 – 请参见下面的代码。

PS:如果您使用 onChangedonEnded 自己管理拖动,则不必使用 @GestureState – 您做了双重工作。我注释掉了你不需要的一切 ;)

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
                }
            }
    }
}