UIScrollView + LargeTitle (iOS 11) - 滚动到顶部并显示大标题

Posted

技术标签:

【中文标题】UIScrollView + LargeTitle (iOS 11) - 滚动到顶部并显示大标题【英文标题】:UIScrollView + LargeTitle (iOS 11) - scroll to top and reveal the large title 【发布时间】:2018-08-17 10:01:51 【问题描述】:

我使用以下代码滚动到 UICollectionView 的顶部:

scrollView.scrollRectToVisible(CGRect(origin: .zero, size: CGSize(width: 1, height: 1)), animated: true)

但是,在 ios 11 和 12 上,scrollView 仅滚动到顶部,而不会显示UINavigationBar 的大标题(当prefersLargeTitle 已设置为true。)

如下所示:

我想要达到的结果:

【问题讨论】:

你的标题是不是变大了?? 没错,滚动视图滚动到顶部后它不会变大。虽然,我可以通过手动拖动滚动视图来恢复它。 我认为这是您无法以编程方式处理此问题的属性。从开发人员端,您只能无法使用此属性,并且当用户上下滚动时,标题将相应放大。 【参考方案1】:

它按设计工作,您正在滚动到位置 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) - 这是与 @ 相同的值987654328@,所以如果你想向上滚动并显示大标题,你应该这样做:

scrollView.scrollRectToVisible(CGRect(x: 0, y: -64, width: 1, height: 1), animated: true)

【讨论】:

-64 效果最好,尽管从adjustedContentInset.top 派生的值更大并且滚动视图“过度滚动”。 这是 Xamarin.iOS 中的有效解决方案,非常感谢您! UICollectionView 的任何解决方案,因为我似乎有同样的问题【参考方案2】:

您不想使用任何“魔法值”(在当前接受的答案中为 -64)。这些可能会改变(另外,-64 也不正确)。

更好的解决方案是观察 SafeAreaInsets 的变化并保存最大的顶部插图。然后在 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)
    

【讨论】:

接受的答案 (-64) 适用于特定问题,但此答案适用于多种不同的情况。我更喜欢此作为最佳答案。【参考方案3】:

似乎使用负内容偏移量是可行的方法。

我真的很喜欢 Demosthese 的想法,以跟踪最大的顶部插图。 但是,这种方法存在一个问题。 有时无法显示大标题,例如,当 iPhone 处于横向模式时。

如果在设备旋转到横向后使用此方法,则表格的偏移量将太大,因为导航栏中不显示大标题。

这项技术的一个改进是仅在导航栏可以显示大标题时才考虑最大的TopSafeAreaInset。 现在的问题是了解导航栏何时可以显示大标题。 我在不同的设备上做了一些测试,当垂直尺寸类紧凑时,似乎没有显示大标题。

因此,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)
        
    

还有一种情况会导致大标题滚动后不显示。

如果用户:

    在横向模式下旋转设备打开应用。 滚动视图。 纵向旋转设备。

此时 maximumTopSafeAreaInset 还没有机会找到最大值,如果调用 scrollToTop 方法,大标题将不会显示。 幸运的是,这种情况不应该经常发生。

【讨论】:

以上是关于UIScrollView + LargeTitle (iOS 11) - 滚动到顶部并显示大标题的主要内容,如果未能解决你的问题,请参考以下文章

如何在当前 vc 上获得 largeTitle,但在 vc 上获得小标题?

带有 UISegmentedControl 和 childViewController 的 iOS LargeTitle(在容器中)

iOS - 方向更改时导航栏不显示大标题

大标题,居中对齐

UIScrollView 内 UIScrollView 内 UIScrollView

UIScrollView 内的 UIScrollView 时滚动