问题
When using large titles and tapping the status bar to scroll to the top of a UIScrollView
or UITableView
(probably also UICollectionView
, haven't tested this) it always goes a little too far.
I have refresh enabled on my TableView
and when tapping the status bar it appears like this and stays that way until I tap the screen.
I have a ScrollView
in another ViewController
and if I tap the status bar there it also scrolls a little bit too far, making the navigation bar too tall. This also returns to normal when I tap somewhere or scroll a tiny bit.
Normal:
After I tapped the status bar:
This also only happens when I have large titles activated, using normal titles everything works as it should.
Any ideas how to fix this?
How to recreate:
- Create a new project with a navigation controller and a
UIViewController
with aTableView
inside. - Set navigation controller to prefer large titles. Turn translucent off. Set title on
UIViewController
- Set constraints on
TableView
to pin to the edges of theViewController
- Create outlet for
TableView
in theViewController
- Implement delegates and set a number of rows, for example 100
- Launch app
- Scroll down so the large title becomes a normal title
- Tap status bar so the
tableView
scrolls to the top
Now the title is not at the position it should be, if you now scroll a tiny bit up or down it snaps back to the normal position.
ViewController
code:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath)
return cell
}
}
回答1:
Okay so I found why the problem occurs, but not how to fix it in that exact scenario.
If you're using large titles and a UITableViewController with the navigation bar translucency set to off the problem will occur. When you turn translucent back on the problem goes away.
If you're using a TableView in a normal UIViewController the problem always occurs.
Edit
Turns out setting "extendedLayoutIncludesOpaqueBars = true" fixes the problem if you're using a translucent navigation bar!
Similar question: UIRefreshControl() in iOS 11 Glitchy effect
回答2:
After many hours of tests i found a solution that works with UIViewController.
In UIViewController with UITableView, you should:
- in viewDidLoad set extendedLayoutIncludesOpaqueBars = true
- in storyboard pin tableView top constraint to superview top with constant = 0 (tableView will be under navigationbar and statusbar when navigationbar is translucent)
After that if you tap on statusbar, tableview stops in the right place.
回答3:
I've fix it with maually setting the contentOffset to 0 after scroll to top.
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
return true
}
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
scrollView.contentOffset.y = 0.0
}
回答4:
In your ViewController declare a var didBeginScrollToTop of Bool type. Assign the controller as scrollView's delegate. Then
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
didBeginScrollToTop = true
return true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard didBeginScrollToTop, scrollToTopGestureTargetView?.contentOffset.y ?? 0 < -25 else { return }
scrollToTopGestureTargetView?.setContentOffset(.zero, animated: true)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
didBeginScrollToTop = false
}
What this does is adjusting your content offset when bouncing. The flag is there to catch the scrollToTop gesture and is reset on scroll. You can also set it off after setting the .zero offset. If you have implementation with child VCs, don't forget to call super when overriding those 3 delegate methods. Now my first approach was to track when the content offSet is < 0, but on some devices it did not expand the navigation item and that magic -25 seemed to work on all simulators. You can combine this approach with an implementation that returns the size of the nav bar and replace it, but as far as I am aware there wasn't an easy way to get the nav bar frame/bounds so easily.
Note you may have to handle also this: Strange velocity prefers large title
来源:https://stackoverflow.com/questions/50625225/ios-11-scroll-to-top-when-using-large-titles-doesnt-work-properly