diff --git a/dimensionhub/Views/Index/IndexMainView.swift b/dimensionhub/Views/Index/IndexMainView.swift index 306345b..9d1ae3e 100644 --- a/dimensionhub/Views/Index/IndexMainView.swift +++ b/dimensionhub/Views/Index/IndexMainView.swift @@ -28,9 +28,8 @@ struct IndexMainView: View { @State private var footerRefreshing: Bool = false @State private var noMore: Bool = false - // 控制显示区域的可见性 - @State private var footerPublisher = PassthroughSubject() - @State var cancel: AnyCancellable? + // 保存底部元素在global坐标系里面的minY值 + @State private var footerOffset: Int = 0 var body: some View { VStack(alignment: .center) { @@ -76,18 +75,33 @@ struct IndexMainView: View { } } - Rectangle() - .frame(height: 0) - .background(GeometryReader { geometry in - Color.clear.onChange(of: geometry.frame(in: .global).minY) { _, newValue in - footerPublisher.send(Int(newValue)) - } - }) - ProgressView() + .background(GeometryReader { geometry in + let minY = geometry.frame(in: .global).minY + Color.clear.preference(key: FooterOffsetPreferenceKey.self, value: Int(minY)) + }) } .frame(width: 370) .coordinateSpace(name: "indexScrollView") + .onScrollPhaseChange { oldPhase, newPhase in + print("scroll old: \(oldPhase), new: \(newPhase), footer-offset: \(footerOffset)") + guard !footerRefreshing && !showDateNavPopover else { + return + } + + // 滑动停止的时候,检测是否到达了底部 + let height = Int(UIScreen.main.bounds.height) + if newPhase == .idle && self.footerOffset < height + 500 { + self.footerRefreshing = true + Task { + await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .next) + await MainActor.run { + self.footerRefreshing = false + } + } + } + + } .refreshable { guard !self.showDateNavPopover && !self.headerRefreshing else { return @@ -143,29 +157,13 @@ struct IndexMainView: View { indexModel.setFixedDrameGroup(groupId: minFrame.key) } } - .onAppear { - cancel = footerPublisher - .debounce(for: 0.1, scheduler: RunLoop.main) - .sink { offset in - guard !footerRefreshing && !showDateNavPopover else { - return - } - - let height = Int(UIScreen.main.bounds.height) - if offset < height + 500 && !footerRefreshing { - self.footerRefreshing = true - Task { - await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .next) - await MainActor.run { - self.footerRefreshing = false - } - } - } - } - } - .onDisappear { - self.cancel?.cancel() + .onPreferenceChange(FooterOffsetPreferenceKey.self) { offset in + // 延迟到当前帧结束更新state的值,避免导致循环更新的警告 + DispatchQueue.main.async { + self.footerOffset = offset + } } + } } @@ -249,6 +247,12 @@ extension IndexMainView { } } + +} + +// MARK: PreferenceKey +extension IndexMainView { + // 元素的坐标的距离变化, [groupId : minY] struct DramaGroupElementPreferenceKey: PreferenceKey { static var defaultValue: [String: CGFloat] = [:] @@ -258,8 +262,21 @@ extension IndexMainView { } } + // 底部的元素的坐标信息变化 + struct FooterOffsetPreferenceKey: PreferenceKey { + static var defaultValue: Int = 0 + + static func reduce(value: inout Int, nextValue: () -> Int) { + let newValue = nextValue() + if newValue > 0 && abs(newValue - value) >= 50 { + value = newValue + } + } + } + } + #Preview { IndexMainView() } diff --git a/dimensionhub/dimensionhubApp.swift b/dimensionhub/dimensionhubApp.swift index 5b7b90b..f2e2dc8 100644 --- a/dimensionhub/dimensionhubApp.swift +++ b/dimensionhub/dimensionhubApp.swift @@ -43,8 +43,8 @@ struct dimensionhubApp: App { var body: some Scene { WindowGroup { NavigationStack(path: $appNav.path) { - //IndexView() - TestView() + IndexView() + //TestView() .navigationDestination(for: AppNavigation.Destination.self) { dest in switch dest { case .detail(id: let id):