UIScrollView + LargeTitle (iOS 11) - 滚动到顶部并显示大标题
UIScrollView + LargeTitle (iOS 11) - scroll to top and reveal the large title
我使用以下代码滚动到 UICollectionView 的顶部:
scrollView.scrollRectToVisible(CGRect(origin: .zero, size: CGSize(width: 1, height: 1)), animated: true)
但是,在 iOS 11 和 12 上,scrollView 仅滚动到顶部,而不会显示 UINavigationBar
的大标题(当 prefersLargeTitle
已设置为 true
.)
这是它的样子:
我想要达到的结果:
它按设计工作,您正在滚动到位置 y = 0
,将您的 controller
分配给 UIScrollView
委托并打印出滚动偏移量:
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView.contentOffset)
}
您将看到何时显示大标题并且您移动滚动视图 a 但是它跳回到大标题它不会打印 (0.0, 0.0)
但 (0.0, -64.0)
或 (0.0, -116.0)
- 这与 scrollView.adjustedContentInset
的值相同,所以如果你想向上滚动并显示大标题,你应该这样做:
scrollView.scrollRectToVisible(CGRect(x: 0, y: -64, width: 1, height: 1), animated: true)
您不想使用任何 'magic values'(如当前接受的答案中的 -64)。这些可能会改变(另外,-64 无论如何都不正确)。
更好的解决办法是观察SafeAreaInsets的变化,保存最大的top inset。然后在 setContentOffset 方法中使用该值。像这样:
class CollectioViewController: UIViewController {
var biggestTopSafeAreaInset: CGFloat = 0
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
self.biggestTopSafeAreaInset = max(ui.safeAreaInsets.top, biggestTopSafeAreaInset)
}
func scrollToTop(animated: Bool) {
ui.scrollView.setContentOffset(CGPoint(x: 0, y: -biggestTopSafeAreaInset), animated: animated)
}
}
看来使用负内容偏移是可行的方法。
我真的很喜欢 Demosthese 跟踪最大顶部插图的想法。
但是,这种方法存在一个问题。
有时无法显示大标题,例如,当 iPhone 处于横向模式时。
如果在设备旋转到横向后使用此方法,则 table 的偏移量会太大,因为大标题不会显示在导航栏中。
该技术的一个改进是仅当导航栏可以显示大标题时才考虑biggestTopSafeAreaInset。
现在的问题是了解导航栏何时可以显示大标题。
我在不同的设备上做了一些测试,当垂直尺寸 class 很紧凑时,似乎不会显示大标题。
所以,Demosthese解决方案可以这样改进:
class TableViewController: UITableViewController {
var biggestTopSafeAreaInset: CGFloat = 0
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
self.biggestTopSafeAreaInset = max(view.safeAreaInsets.top, biggestTopSafeAreaInset)
}
func scrollToTop(animated: Bool) {
if traitCollection.verticalSizeClass == .compact {
tableView.setContentOffset(CGPoint(x: 0, y: -view.safeAreaInsets.top), animated: animated)
} else {
tableView.setContentOffset(CGPoint(x: 0, y: -biggestTopSafeAreaInset), animated: animated)
}
}
}
还有一种情况会导致滚动后大标题不显示
如果用户:
- 在横向模式下旋转设备打开应用程序。
- 滚动视图。
- 纵向旋转设备。
此时biggestTopSafeAreaInset还没有找到最大值,如果调用scrollToTop方法则不会显示大标题。
幸运的是,这种情况不应该经常发生。
我使用以下代码滚动到 UICollectionView 的顶部:
scrollView.scrollRectToVisible(CGRect(origin: .zero, size: CGSize(width: 1, height: 1)), animated: true)
但是,在 iOS 11 和 12 上,scrollView 仅滚动到顶部,而不会显示 UINavigationBar
的大标题(当 prefersLargeTitle
已设置为 true
.)
这是它的样子:
我想要达到的结果:
它按设计工作,您正在滚动到位置 y = 0
,将您的 controller
分配给 UIScrollView
委托并打印出滚动偏移量:
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView.contentOffset)
}
您将看到何时显示大标题并且您移动滚动视图 a 但是它跳回到大标题它不会打印 (0.0, 0.0)
但 (0.0, -64.0)
或 (0.0, -116.0)
- 这与 scrollView.adjustedContentInset
的值相同,所以如果你想向上滚动并显示大标题,你应该这样做:
scrollView.scrollRectToVisible(CGRect(x: 0, y: -64, width: 1, height: 1), animated: true)
您不想使用任何 'magic values'(如当前接受的答案中的 -64)。这些可能会改变(另外,-64 无论如何都不正确)。
更好的解决办法是观察SafeAreaInsets的变化,保存最大的top inset。然后在 setContentOffset 方法中使用该值。像这样:
class CollectioViewController: UIViewController {
var biggestTopSafeAreaInset: CGFloat = 0
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
self.biggestTopSafeAreaInset = max(ui.safeAreaInsets.top, biggestTopSafeAreaInset)
}
func scrollToTop(animated: Bool) {
ui.scrollView.setContentOffset(CGPoint(x: 0, y: -biggestTopSafeAreaInset), animated: animated)
}
}
看来使用负内容偏移是可行的方法。
我真的很喜欢 Demosthese 跟踪最大顶部插图的想法。 但是,这种方法存在一个问题。 有时无法显示大标题,例如,当 iPhone 处于横向模式时。
如果在设备旋转到横向后使用此方法,则 table 的偏移量会太大,因为大标题不会显示在导航栏中。
该技术的一个改进是仅当导航栏可以显示大标题时才考虑biggestTopSafeAreaInset。 现在的问题是了解导航栏何时可以显示大标题。 我在不同的设备上做了一些测试,当垂直尺寸 class 很紧凑时,似乎不会显示大标题。
所以,Demosthese解决方案可以这样改进:
class TableViewController: UITableViewController {
var biggestTopSafeAreaInset: CGFloat = 0
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
self.biggestTopSafeAreaInset = max(view.safeAreaInsets.top, biggestTopSafeAreaInset)
}
func scrollToTop(animated: Bool) {
if traitCollection.verticalSizeClass == .compact {
tableView.setContentOffset(CGPoint(x: 0, y: -view.safeAreaInsets.top), animated: animated)
} else {
tableView.setContentOffset(CGPoint(x: 0, y: -biggestTopSafeAreaInset), animated: animated)
}
}
}
还有一种情况会导致滚动后大标题不显示
如果用户:
- 在横向模式下旋转设备打开应用程序。
- 滚动视图。
- 纵向旋转设备。
此时biggestTopSafeAreaInset还没有找到最大值,如果调用scrollToTop方法则不会显示大标题。 幸运的是,这种情况不应该经常发生。