SwiftUI - How to Tell When a User Interacts with the Scroll View and not Programmatically?
Asked Answered
C

0

7

I am trying to find out when the user interacts with a horizontal ScrollView in SwiftUI. The problem is that most solutions that I have found are based around when the scroll view moves. This doesn't work as the scroll view also moves without the user actually moving it. This example should show what I am essentially trying to do with my app:

import SwiftUI
import UIKit

struct ContentView: View {
    
    @State var colors: [Color] = [Color.orange, Color.blue, Color.green, Color.pink]
    @State var target = 0
    
    var body: some View {
        VStack {
            ScrollViewReader { value in
                ScrollView(.horizontal) {
                    HStack(spacing: 20) {
                        ForEach(0..<100) { i in
                            Rectangle().fill(colors[i % colors.count]).frame(width: 350, height: 350)
                                .id(i)
                        }
                    }
                }
                HStack {
                    Button("Up") {
                        target += 1
                        withAnimation(){
                            value.scrollTo(target, anchor: .center)
                        }
                    }
                    Spacer()
                    Button("Down") {
                        target -= 1
                        withAnimation(){
                            value.scrollTo(target, anchor: .center)
                        }
                    }
                }
                .padding()
            }
        }
    }
}

I'm trying to get the app to tell me when the user is moving the scroll view vs when "the app" moves the scroll view (as shown through the up and down buttons).

When I try and use Drag Gestures they lock the scroll view, even with a Tap Gesture before it. Changing the minimumDistance will make only one of the actions fire, either the gesture or the scroll view, and not simultaneously.

.onTapGesture { }
.simultaneousGesture(
    DragGesture(minimumDistance: 0)
        .onChanged { _ in
            print("moving")
        }
        .onEnded { _ in
            print("stopped")
        })

And something like this doesn't work as when the scroll view moves programmatically it would be detected as the user moving it.

How can I get the app to know whether the scroll view is being moved by the user and when it is being moved programmatically?

Caddell answered 22/2, 2022 at 23:23 Comment(5)
When you say "the app" moves the scroll view do you mean the user click a button and the action you wrote to moves the scroll view?Webfoot
The buttons are there to simulate what my real app will be doing. I want my app to move the scroll view automatically, and the buttons are just there for the example.Caddell
you can use the answer in your link to detect moves, and when you move programmatically, just set a flag. So when you receive the publisher just check the flag and you know.Durno
Hello! Did you find a solution or maybe workaround? Thanks.Kriemhild
@MrDuck Did you ever find a solution to this?Junco

© 2022 - 2025 — McMap. All rights reserved.