iOS 11大型导航栏标题出现意外速度

45

我正在尝试在我的新应用程序中实现iOS 11原生的大型导航栏标题。通过在viewDidLoad()中调用以下函数:

navigationController?.navigationBar.prefersLargeTitles = true navigationController?.navigationItem.largeTitleDisplayMode = .always

我得到了我想要的效果。 enter image description here

但是,当我开始向上滚动(主视图中唯一的视图是滚动视图),滚动使大标题消失的速度比实际手指滚动的速度快。也就是说,如果我在屏幕上移动2cm,则滚动视图实际上会滚动更多,直到大标题缩小为“通常”大小。

下面是我的应用程序被滚动的gif。我实际上移动的很少,它自动向上滚动那么多。这与苹果制作的应用程序不同(例如,在我的应用程序下面显示的应用商店)。

有没有人有解决这种异常行为的解决方案?

enter image description here

enter image description here

编辑: 按照要求,我添加了当前的视图层次结构。我的代码中没有任何特殊之处,我只是设置了标题和prefersLargeTitles标志。

enter image description here


我在模拟器上尝试了一下,行为比你的示例慢。这与App Store的scrollView动画相同。如果我向上滚动到大标题的一半不可见,它会自动滚动到最顶部。这不是您期望看到的行为吗? - Dorukhan Arslan
@DorukhanArslan,App Store的scrollView在手指仍然触摸屏幕时,您可以停在任何位置并保持不动,直到您松开手指。但是我的应用程序即使手指还在屏幕上,它也会自动滚动到顶部。 - Seop Yoon
@DorukhanArslan 为了提供更多信息,向下滚动内容(即向上移动手指)会使标题突然快速更改,而向上滚动内容(即向下移动手指)则表现如预期。 - Seop Yoon
1
@DorukhanArslan 我添加了视图层次结构! - Seop Yoon
1
可能是 Smooth scrolling with prefersLargeTitles and UITableView 的重复问题。 - Jakub Truhlář
显示剩余2条评论
6个回答

49

我用以下约束条件解决了这个问题:

    NSLayoutConstraint.activate([
        scrollView.topAnchor.constraint(equalTo: view.topAnchor),
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor)
        ])

你还需要在你的UIViewController子类上设置此属性:

extendedLayoutIncludesOpaqueBars = YES

11
我只需要设置extendedLayoutIncludesOpaqueBars,就可以了。谢谢。我甚至不知道这个属性存在。 - dezinezync
1
extendedLayoutIncludesOpaqueBars = YES可以实现这个功能。谢谢。 - Toma Radu-Petrescu
太棒了!!我只使用了属性! - Rodrigo Fuscaldi
当将该属性设置为true时,外观和感觉会有天壤之别! - DogCoffee
2
当使用containerview作为childviewcontroller时,我通过将此containerview的约束附加到superview而不是安全区域来解决了这个问题。我从您的答案中得到了这个想法,非常感谢! :) - Bob de Graaf

35

我也遇到了这个问题。

在Interface Builder中

  1. 选择你的"viewController"
  2. 属性检查器勾选"Under Opaque Bars"和"Under Top Bars"
  3. 将你的scrollView的顶部约束的第二项设置为"SuperView"而不是"SafeArea"

2
第三项对我有用。 - Joris Weimar
1
第三项对我也起了作用。 - Davuth
两者都是必要的。谢谢!现在它正在运行。 - surfrider

9

我已经调试了几天,找到了一个解决方法。

首先,出现了什么问题?

UIScrollView与大标题不兼容,导致性能下降。由于在滚动视图上向上滚动时,导航栏变小,所以与实际滚动相比存在两倍的滚动。

我通过有意设置来确认了这一点:

scrollView.contentOffset.y = scrollView.contentOffset.y * 0.5

这确实使它按预期移动。但是,这不能解决整个问题,因为在从大型导航栏切换到小型导航栏时没有产生平滑的过渡。你可以尝试下面的代码。

if scrollView.contentOffset.y > 0 {
  if self.navigationController!.navigationBar.frame.size.height > 44.0 {
    scrollView.contentOffset.y = scrollView.contentOffset.y * 0.5
  }
}

在缓慢滚动时,这种方法运行得还可以,但是当您向下快速滑动时,它会在一开始时变慢(导航栏高度很大),然后加速。

解决方法

简单来说,您不能在iOS 11的大型导航栏中使用 UIScrollView,而应该使用 UITableViewController
由于我的视图由多个水平的UICollectionViews组成,沿着垂直方向展开,所以我使用了不同部分的UITableView来使用storyboard构建UI。 如果您使用UITableViewController,它将按预期执行。
App Store和所有其他Apple制作的原生应用都必须这样做。


我在使用带有大标题的UITableView时也遇到了同样的问题,有什么解决办法吗? - Bucket
@barbarity 我在上面的回答中犯了一个错误。它只适用于使用UITableViewController而不是在UIViewController中使用UITableView。(将修改上面的回答) - Seop Yoon
1
不错的发现!整个大标题导航栏都是一个令人羞愧、有缺陷的API... - Tamás Zahola
当使用UITableViewController和UISearchController时,此错误也会发生。因此我们可以一致认为大标题非常有问题。我不知道Whats App如何同时拥有searchController和平滑滚动。 - Lucas P.
我不同意这应该是批准的答案。有时候需要滚动视图。这与此处提供的答案有类似的解决方案:https://stackoverflow.com/a/55523549/1909108 - Tyten

7
我发现当导航栏标题较大且不透明时,会出现此问题。如果您正在使用CollectionView或TableView,并且它受到安全区域或其父视图的约束,则应该为您处理插图。
对于滚动视图,请查看苹果文档,其中介绍了一些新变量(例如contentInsetAdjustmentBehavior),用于iOS 11中引入的安全区域更改: https://developer.apple.com/documentation/uikit/uiscrollview 使导航栏透明 在viewDidLoad()中,尝试添加以下内容:
navigationController?.navigationBar.isTranslucent = true

或者在 IB 中设置此勾选框:

半透明勾选框


你可以展示一些代码来实现这个,这样会更容易让其他人决定你的回答是否有帮助。 - Murmel
只是说,集合视图/表视图 滚动视图,因此它们具有相同的属性。 - Kane Cheshire
1
是的,那是真的,这就是为什么我链接到滚动视图文档的原因 :) - JWhitey

6
在双倍速度的情况下可能会存在问题,即您的视图大小小于导航控制器视图大小,并且您具有以下视图层次结构(可以在视图调试器中检查): V:|-[navbar]-[view]-| 因此,在滚动时,内容偏移发生变化并且视图框架也会发生变化,这就是双倍速度的原因。 extendedLayoutIncludesOpaqueBars = true 应该有所帮助。

5

首先,请确保scrollView的顶部约束的第二个项目等于Superview.Top,而不是Safe Area

其次,在您的视图控制器中添加这一行代码:extendedLayoutIncludesOpaqueBars = true。例如在viewDidLoad 中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接