From 721dd315b24adbea25a74e9b49fa9490405a24b7 Mon Sep 17 00:00:00 2001 From: David Christiandy <1299411+dvdchr@users.noreply.github.com> Date: Tue, 5 Mar 2024 21:25:24 +0700 Subject: [PATCH 1/2] Restore the native scroll-to-top behavior --- .../Reader/Tab Navigation/ReaderTabView.swift | 21 +++++++++++++++++++ .../ReaderTabViewController.swift | 1 + 2 files changed, 22 insertions(+) diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift index f9fa96bf2ca3..92c2e6ebdedf 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift @@ -155,6 +155,19 @@ extension ReaderTabView { self.filteredTabs.append((index: selectedIndex, topic: selectedTopic)) } + /// Disables the `scrollsToTop` property for the scroll views created from SwiftUI. + /// To preserve the native scroll-to-top behavior when the status bar is tapped, there + func disableScrollsToTop() { + var viewsToTraverse = navigationMenu.subviews + while viewsToTraverse.count > 0 { + let subview = viewsToTraverse.removeFirst() + if let scrollView = subview as? UIScrollView { + scrollView.scrollsToTop = false + } + viewsToTraverse.append(contentsOf: subview.subviews) + } + } + private func updateMenuDisplay(hidden: Bool) { guard isMenuHidden != hidden else { return } @@ -212,6 +225,7 @@ extension ReaderTabView: ReaderNavigationMenuDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView, velocity: CGPoint) { let isContentOffsetNearTop = scrollView.contentOffset.y < scrollView.frame.height / 2 + let isContentOffsetAtTop = scrollView.contentOffset.y == .zero let isUserScrollingDown = velocity.y < -400 let isUserScrollingUp = velocity.y > 400 @@ -223,6 +237,13 @@ extension ReaderTabView: ReaderNavigationMenuDelegate { updateMenuDisplay(hidden: false) } + // Handles the native scroll-to-top behavior (by tapping the status bar). + // Somehow the `scrollViewDidScrollToTop` method is not called in the view controller + // containing the scroll view, so we'll need to put a custom logic here instead. + if isMenuHidden && isContentOffsetAtTop { + updateMenuDisplay(hidden: false) + } + // Accounts for a user scrolling slowly enough to not trigger displaying the menu near the top of the content if isMenuHidden && isContentOffsetNearTop && velocity.y > 0 { updateMenuDisplay(hidden: false) diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift index 808b2c751f80..b583eeeeab0a 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift @@ -52,6 +52,7 @@ class ReaderTabViewController: UIViewController { super.viewDidAppear(animated) ReaderTracker.shared.start(.main) + readerTabView.disableScrollsToTop() if AppConfiguration.showsWhatIsNew { RootViewCoordinator.shared.presentWhatIsNew(on: self) From 5993d7ddc04d4fdc06243214ef51844c9094ffcd Mon Sep 17 00:00:00 2001 From: David Christiandy <1299411+dvdchr@users.noreply.github.com> Date: Tue, 5 Mar 2024 21:41:21 +0700 Subject: [PATCH 2/2] Fix documentation --- .../ViewRelated/Reader/Tab Navigation/ReaderTabView.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift index 92c2e6ebdedf..fe6663ec7a3b 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift @@ -156,7 +156,8 @@ extension ReaderTabView { } /// Disables the `scrollsToTop` property for the scroll views created from SwiftUI. - /// To preserve the native scroll-to-top behavior when the status bar is tapped, there + /// To preserve the native scroll-to-top behavior when the status bar is tapped, there could only be + /// one scroll view on screen with the `scrollsToTop` property set to `true`. func disableScrollsToTop() { var viewsToTraverse = navigationMenu.subviews while viewsToTraverse.count > 0 {