0

anyone know how to toggle gestures between subviews?

I have a TabView that is made up of 3 pages. Swiping on the page navigates me to another page. In one of the pages, I used Apple's Chart API, that contains a Drag Gesture. Idea is to longPress on the Chart to enable the drag gesture of the chart, else, a swipe on the Chart will use the TabView's drag gesture to slide to next page. But when trying to swipe on the chart, the TabView's swipe gesture isn't recognized. It's only recognized outside of the chart. Any idea on how to disable Chart gestures until longPressed gesture, within my Chart's view, is completed?

I looked into using .allowHitTesting modifier to disable Charts but I wasn't able to toggle it on upon longPressed as all hit detection is disabled. Any ideas?

struct HomePageDetailView: View {

@State var allowHit = false

var body: some View {
    TabView {
        HomePageChartDetailView()
        Color.red
        Color.blue
    }
    .tabViewStyle(.page)
  }
}

HomePageChartDetailView

struct HomePageChartDetailView: View {

@State var range: (Date, Date)? = nil
@GestureState var initialdragState = false
@State var enablePriceDrag = false

@State var startItemIndex = 0
@State var currentItemIndex = 0
 ...

var body: some View {
    
    let longPress = LongPressGesture(minimumDuration: 0.5)
        .onEnded { value in
            self.enablePriceDrag.toggle()
        }
    
    VStack(alignment: .leading) {
        Picker("Date Chosen", selection: $selectedTimeLine) {
            ...
        }
        
        Chart(data, id: \.id) { stock in
            LineMark(x: .value("Index", stock.formattedDate), y: .value("Value", stock.close)) 
            
            AreaMark(x: .value("Index", stock.formattedDate), y: .value("Value", stock.close))
              
            if let (start, end) = range, enablePriceDrag {
                RectangleMark(xStart: .value("Range", start), xEnd: .value("Range End", end))
                    .foregroundStyle(.red)
            }
        }
        
        .chartAxisModifier(value: $enablePriceDrag)
        
        .chartOverlay(content: { proxy in
            GeometryReader { g in
                Rectangle().fill(.clear).contentShape(Rectangle())
                    .gesture(
                        longPress
                            .sequenced(before: DragGesture(minimumDistance: 0)
                                .updating($initialdragState, body: { gesture, value, transaction in
                                })
                                    .onChanged { value in
                                        let startX = value.startLocation.x
                                        let currentX = value.location.x
                                        let endX = g[proxy.plotAreaFrame].width
                                        let xOrigin = g[proxy.plotAreaFrame].origin.x
                                          
                                        ///Retrieves Each Price Object in Chart
                                        let eachItem = endX / CGFloat(data.count)
                                        
                                        let startItemIndex = Int(startX / eachItem)
                                        let tempItemIndex = Int(currentX / eachItem)
                                        
                                        self.startItemIndex = startItemIndex
                                        
                                        currentItemIndex = tempItemIndex
                                        
                                        ///Find the date values at the x coordinates. 
                                        if let startDate: Date = proxy.value(atX: startX),
                                           let currentDate: Date = proxy.value(atX: currentX),
                                           let endDate: Date = proxy.value(atX: endX),
                                           let originDate: Date = proxy.value(atX: xOrigin),
                                           startDate < endDate && currentDate < endDate,
                                           currentDate > originDate {
                                            range = (startDate, currentDate)
                                        }
                                    }
                                       
                                .onEnded { _ in
                                    enablePriceDrag = false
                                    range = nil
                                }))
            }
        })
    }
}

Image for reference:

enter image description here

Kenny Ho
  • 409
  • 3
  • 16
  • Does this answer your question? [Conditionnaly activate Gesture in SwiftUI](https://stackoverflow.com/questions/71469248/conditionnaly-activate-gesture-in-swiftui) – lorem ipsum Apr 15 '23 at 16:44
  • Close, but i found the actual solution here. https://stackoverflow.com/questions/68333347/swiftui-detecting-long-press-while-keeping-tabview-swipable/68367398#68367398 Basically had to create a custom tabView. – Kenny Ho Apr 21 '23 at 15:09

0 Answers0