Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reader: Restore the native scroll-to-top behavior #22771

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ 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 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 {
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 }

Expand Down Expand Up @@ -212,6 +226,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

Expand All @@ -223,6 +238,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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ReaderTabViewController: UIViewController {
super.viewDidAppear(animated)

ReaderTracker.shared.start(.main)
readerTabView.disableScrollsToTop()

if AppConfiguration.showsWhatIsNew {
RootViewCoordinator.shared.presentWhatIsNew(on: self)
Expand Down
Loading