SwiftUI-检测ScrollView何时完成滚动? [英] SwiftUI - Detect when ScrollView has finished scrolling?

查看:49
本文介绍了SwiftUI-检测ScrollView何时完成滚动?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要找出我的 ScrollView 停止移动的确切时间.SwiftUI有可能吗?

  import合并struct ContentView:查看{让检测器:CurrentValueSubject< CGFloat,Never>.让发布者:AnyPublisher< CGFloat,Never>在里面() {让检测器= CurrentValueSubject< CGFloat,从不>(0)self.publisher =检测器.debounce(for:.seconds(0.2),Scheduler:DispatchQueue.main).dropFirst().eraseToAnyPublisher()self.detector =检测器}var body:some View {ScrollView {VStack(间距:20){ForEach(0 ... 100,id:\ .self){我在长方形().frame(宽度:200,高度:100).foregroundColor(.green).overlay(Text("\(i)"))}}.frame(maxWidth:.infinity).background(GeometryReader {Color.clear.preference(key:ViewOffsetKey.self,值:-$ 0.frame(in:.named("scroll")).origin.y)}).onPreferenceChange(ViewOffsetKey.self){detector.send($ 0)}} .coordinateSpace(名称:滚动").onReceive(发布商){print(停止于:\($ 0)")}}} 

I need to find out the exact moment when my ScrollView stops moving. Is that possible with SwiftUI?

Here would be an equivalent for UIScrollView.

I have no idea after thinking a lot about it...

A sample project to test things out:

struct ContentView: View {
    
    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                ForEach(0...100, id: \.self) { i in
                    Rectangle()
                        .frame(width: 200, height: 100)
                        .foregroundColor(.green)
                        .overlay(Text("\(i)"))
                }
            }
            .frame(maxWidth: .infinity)
        }
    }
}

Thanks!

解决方案

Here is a demo of possible approach - use publisher with changed scrolled content coordinates with debounce, so event reported only after coordinates stopped changing.

Tested with Xcode 12.1 / iOS 14.1

Note: you can play with debounce period to tune it for your needs.

import Combine

struct ContentView: View {
    let detector: CurrentValueSubject<CGFloat, Never>
    let publisher: AnyPublisher<CGFloat, Never>

    init() {
        let detector = CurrentValueSubject<CGFloat, Never>(0)
        self.publisher = detector
            .debounce(for: .seconds(0.2), scheduler: DispatchQueue.main)
            .dropFirst()
            .eraseToAnyPublisher()
        self.detector = detector
    }
    
    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                ForEach(0...100, id: \.self) { i in
                    Rectangle()
                        .frame(width: 200, height: 100)
                        .foregroundColor(.green)
                        .overlay(Text("\(i)"))
                }
            }
            .frame(maxWidth: .infinity)
            .background(GeometryReader {
                Color.clear.preference(key: ViewOffsetKey.self,
                    value: -$0.frame(in: .named("scroll")).origin.y)
            })
            .onPreferenceChange(ViewOffsetKey.self) { detector.send($0) }
        }.coordinateSpace(name: "scroll")
        .onReceive(publisher) {
            print("Stopped on: \($0)")
        }
    }
}

这篇关于SwiftUI-检测ScrollView何时完成滚动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆