SwiftUI:列表中单个item滑动时的翻页效果

1、代码如下:


import SwiftUI

let kWidth = UIScreen.main.bounds.width

struct SPScrollTestView: View {
    
    @State private var offset: CGFloat = 0.0
    /// 上一次的offset,判断滚动方向
    @State private var lastOffset: CGFloat = 0.0
    /// 滚动状态
    @State private var isScrolling: Bool = false
    /// 是否往上滑动
    @State private var toTop: Bool = true
    /// 是否可以自动滚动
    @State private var canScroll: Bool = false
    
    var body: some View {
        GeometryReader { proxy in
            ScrollViewReader(content: { scrollProxy in
                ScrollView(.vertical) {
                    GeometryReader { geometry in
                        Color.clear.preference(key: ViewOffsetKey.self, value: geometry.frame(in: .named("scrollView")).minY)
                    }.frame(height: 0)
                    LazyVStack(spacing:10) {
                        ForEach(0..<10) { i in
                            GeometryReader { reader in
                                ZStack {
                                    Rectangle()
                                        .fill(Color.yellow)
                                    Text("Page: \(i)")
                                        .bold()
                                }
                                .frame(width: kWidth,height: 300 + CGFloat(50 * i))
                                .cornerRadius(5)
                                .shadow(radius: 5)
                                .id("scroll\(i)")
                                .onChange(of: canScroll) { _ in
                                    if canScroll {
                                        let minY = reader.frame(in: .global).minY
                                        //                                        let midY = reader.frame(in: .global).midY
                                        let maxY = reader.frame(in: .global).maxY
                                        let height = reader.size.height
                                        if toTop {
                                            if minY < 0 ,maxY > 0 {
                                                print("========================【上】================================")
                                                if abs(minY) > height / 3 {
                                                    withAnimation {
                                                        scrollProxy.scrollTo("scroll\(i+1)", anchor: .top)
                                                    }
                                                } else {
                                                    withAnimation {
                                                        scrollProxy.scrollTo("scroll\(i)", anchor: .top)
                                                    }
                                                }
                                            }
                                        } else {
                                            if minY < offset,maxY < height,maxY > 0 {
                                                if maxY > height / 4 {
                                                    withAnimation {
                                                        scrollProxy.scrollTo("scroll\(i)", anchor: .top)
                                                    }
                                                } else {
                                                    withAnimation {
                                                        scrollProxy.scrollTo("scroll\(i+1)", anchor: .top)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }.frame(width: kWidth,height: 300 + CGFloat(50 * i))
                        }
                    }
                    
                }
                .coordinateSpace(name:"scrollView")
                .onChange(of: isScrolling) { _ in
                    canScroll = !isScrolling
                    if isScrolling == false {
                        if lastOffset < offset { // 往上
                            toTop = true
                        } else {
                            toTop = false
                        }
                        lastOffset = offset
                    } else {
                        lastOffset = offset
                    }
                }
                .onPreferenceChange(ViewOffsetKey.self) { offset in
                    if offset > 0 { return }
                    self.offset = -offset
                }
                .scrollStatusMonitor($isScrolling, monitorMode: .exclusion)
            })
        }.ignoresSafeArea()
    }
}

#Preview {
    SPScrollTestView()
}

//计算scroll 偏移量
struct ViewOffsetKey: PreferenceKey {
    typealias Value = CGFloat

    static var defaultValue: CGFloat = 0

    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value += nextValue()
    }
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容