簡體   English   中英

SwiftUI ScrollView手勢識別器

[英]SwiftUI ScrollView gesture recogniser

如何檢測何時拖動 ScrollView?

在我的 ScrollView 中,我有一個@Binding scrollPositionOffset變量,我使用.onChange(of:)觀看,然后使用ScrollViewReader.scrollTo()以編程方式滾動到 position 。 這很好用,但是當我直接滾動 ScrollView 時,我還需要更新scrollPositionOffset 我正在努力做到這一點,因為這會觸發.onChange(of:)閉包並進入循環。

我的解決方案是僅在我將localScrolling變量設置為 false 時有條件地調用ScrollViewReader.scrollTo() 我嘗試使用DragGesture.onChanged.onEnded進行設置,但這與導致滾動的拖動手勢不同,因此.onEnded永遠不會觸發。

我認為我需要的是一個類似於 UIScrollView 的isDraggingisTracking的 ScrollView 的 @GestureRecognizer(我知道我可以使用 UIScrollView,但我不知道怎么做,而且這似乎可能更有效!!我會接受一個向我展示如何將其放入 SwiftUIView 的答案)

上下文(如果有人對我的實際情況有更清潔的解決方案):

我有一個 ScrollView,我正在以編程方式滾動以創建類似於 Xcode 中的 Minimap 視圖的效果(即,我有一個與 ScrollView 相鄰的縮小視圖,並且拖動 minimap 會導致 ScrollView 滾動)。

這在我使用小地圖時效果很好,但我正在努力讓相反的事情發生:移動 ScrollView 的 position 以更新小地圖視圖。

代碼


@Binding var scrollPositionOffset: CGFloat
let zoomMultiplier:CGFloat = 1.5

 var body: some View{
        
        ScrollViewReader { scrollViewProxy in
            GeometryReader{ geometry in
                ScrollView {
                    ZStack(alignment:.top){

         //The content of my ScrollView

                    MagnifierView()
                        .frame(height: geometry.size.height * zoomMultiplier)
                    
         //I'm using this as my offset reference

                        Rectangle()
                            .frame(height:10)
                            .alignmentGuide(.top) { _ in
                                geometry.size.height * zoomMultiplier * -scrollPositionOffset
                            }
                            .id("scrollOffset")    
                    }
                }
                .onAppear(){
                    scrollViewProxy.scrollTo("scrollOffset", anchor: .top)
                }
                
                .onChange(of: scrollPositionOffset, perform: { _ in
            
        //Only call .scrollTo() if the view isn't already being scrolled by the user

                    if !localScrolling {
                    scrollViewProxy.scrollTo("scrollOffset", anchor: .top)
                    }
                    
                })
                
                .gesture(
                    DragGesture()
                        .onChanged{gesture in
                            localScrolling = true
                            
                            let offset = gesture.location.y/(zoomMultiplier * geometry.size.height)

                            scrollPositionOffset = offset
                        }
        
                        .onEnded({gesture in

     //Doesn't ever fire when scrolling

                            localScrolling = false
                        })
                )
            }
        }
    }

使用ScrollViewStyle

struct CustomScrollView: ScrollViewStyle {
    @Binding var isDragging: Bool
    func make(body: AnyView, context: Context) -> some View {
        body
    }
    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }
    class Coordinator: ScrollViewCoordinator {
        var parent: CustomScrollView
        init(parent: CustomScrollView) {
            self.parent = parent
        }
        func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
            parent.isDragging = false
        }
        func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
            parent.isDragging = true
        }
    }
}

struct TestView: View {
    @State var isDragging = false
    var body: some View {
        ScrollView {
            
        }.scrollViewStyle(CustomScrollView(isDragging: $isDragging))
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM