简体   繁体   中英

SwiftUI TapGesture and LongPressGesture in ScrollView with tap indication not working

I'm struggling to implement TapGesture and LongPressGesture simultaneously in a ScrollView. Everything works fine with.onTapGesture and.onLongPressGesture, but I want that the opacity of the button gets reduced when the user taps on it, like a normal Button().

However, a Button() doesn't have an option to do something on a long press for whatever reason. So I tried to use.gesture(LongPressGesture()... ). This approach works and shows the tap indication. Unfortunately, that doesn't work with a ScrollView: you can't scroll it anymore!

So I did some research and I found out that there has to be a TapGesture before the LongPressGesture so ScrollView works properly. That's the case indeed but then my LongPressGesture doesn't work anymore.

Hope somebody has a solution...


struct ContentView: View {
    var body: some View {
        ScrollView(.horizontal){
            HStack{
                ForEach(0..<5){ _ in
                    Button()
                }
            }
        }
    }
}

struct Button: View{
    
    @GestureState var isDetectingLongPress = false
    @State var completedLongPress = false
    
    var body: some View{
        
        Circle()
            .foregroundColor(.red)
            .frame(width: 100, height: 100)
            .opacity(self.isDetectingLongPress ? 0 : 1)
            
            // That works, but there is no indication for the user that the UI recognized the gesture
            //                        .onTapGesture {
            //                            print("Tapped!")
            //                       }
            //                        .onLongPressGesture(minimumDuration: 0.5){
            //                            print("Long pressed!")
            //                        }
            
            
            // The approach (*) shows the press indication, but the ScrollView is stuck because there is no TapGesture
            
            // If I add a dummy TapGesture, the LongPressGesture won't work anymore but now the ScrollView works as expected
            //.onTapGesture {}
            
            // (*)
            .gesture(LongPressGesture()
                .updating(self.$isDetectingLongPress) { currentstate, gestureState,
                    transaction in
                    gestureState = currentstate
            }
            .onEnded { finished in
                self.completedLongPress = finished
                }
        )
    }
}

I've tried many combinations of trying onTapGesture + LongPressGesture + custom timings and animations and many work /almost/ but leave minor annoyances. This is what I found that works perfectly. Tested on iOS 13.6.

With this solution your scroll view still scrolls, you get the button depression animation, long pressing on the button works too.

struct MainView: View {
...
  Scrollview {
    RowView().highPriorityGesture(TapGesture()
      .onEnded { _ in
      // The function you would expect to call in a button tap here.
    })

}
}

struct RowView: View {

@State var longPress = false
var body: some View {
    Button(action: {
        if (self.longPress) {
            self.longPress.toggle()
        } else {
            // Normal button code here
        }
    }) {
// Buttons LaF here
}
// RowView code here.
.simultaneousGesture(LongPressGesture(minimumDuration: 0.5)
  .onEnded { _ in
    self.longPress = true
  })
}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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