使用大标题时 iOS 11 滚动到顶部无法正常工作

Posted

技术标签:

【中文标题】使用大标题时 iOS 11 滚动到顶部无法正常工作【英文标题】:iOS 11 scroll to top when using large titles doesn't work properly 【发布时间】:2018-11-10 12:30:55 【问题描述】:

当使用大标题并点击状态栏以滚动到UIScrollViewUITableView 的顶部(可能还有UICollectionView,尚未对此进行测试)时,它总是有点过头了。

我在TableView 上启用了刷新,当点击状态栏时,它会显示为这样并保持这种状态,直到我点击屏幕。

我在另一个ViewController 中有一个ScrollView,如果我点击那里的状态栏,它也会滚动有点太远,使导航栏太高。当我点击某处或滚动一点点时,这也会恢复正常。

正常:

点击状态栏后:

这也只会在我激活大标题时发生,使用普通标题一切正常。

任何想法如何解决这个问题?

如何重新创建:

    创建一个新项目,其中包含一个导航控制器和一个 UIViewController,其中包含一个 TableView。 将导航控制器设置为首选大标题。关闭半透明。在UIViewController 上设置标题 在TableView 上设置约束以固定到ViewController 的边缘 在ViewController 中为TableView 创建出口 实现委托并设置行数,例如 100 启动应用程序 向下滚动,使大标题变为普通标题 点击状态栏,tableView 滚动到顶部

现在标题不在应有的位置,如果您现在向上或向下滚动一点点,它会迅速回到正常位置。

ViewController代码:

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
    


【问题讨论】:

我创建了一个新项目并放置了大标题并添加了一个刷新控件,在 TableView 中添加了 100 个项目,但我无法重现您的错误。 @Serj 哦,很奇怪,这并不是我在视图控制器中做了很多可能导致这种情况的原因,我会尝试找出我做错了什么,谢谢! 如果您可以为我们提供重现该错误的方法,我们将非常乐意提供帮助。这是有关如何执行此操作的指南***.com/help/mcve @Serj 添加了重新创建的步骤,从头开始,我仍然遇到同样的问题 @Fogmeister 添加(对于从头开始的新项目,因为它也在那里发生,不过它只是基本代码) 【参考方案1】:

好的,所以我找到了问题发生的原因,但不知道如何在那个确切的情况下解决它。

如果您使用大标题和导航栏半透明设置为关闭的 UITableViewController,则会出现问题。 当您重新打开半透明时,问题就消失了。

如果您在普通 UIViewController 中使用 TableView,问题总是会发生。

编辑

事实证明,如果您使用的是半透明导航栏,设置“extendedLayoutIncludesOpaqueBars = true”可以解决问题!

类似问题:UIRefreshControl() in ios 11 Glitchy effect

【讨论】:

在普通的 UIViewController 中使用 tableView 有没有找到解决办法? @FrédéricAdda 请检查我的适用于 UIViewController 的答案【参考方案2】:

我遇到了同样的问题。我在 UINavigationController 中嵌入了 UIViewController 中的 collectionview。 Collectionview 对安全区域有前导、尾随、顶部、底部约束。

要解决此问题,您需要:

    将collectionview的top约束改为supervises(非安全区域) 在 viewDidLoad 方法中设置 extendedLayoutIncludesOpaqueBars = true

【讨论】:

稍微解决了这个问题,但完整的解决方案只是:self.tableView.scrollRectToVisible(CGRect(x: 0.0, y: 0.0, width: 1, height: 1), animated: true)【参考方案3】:

经过数小时的测试,我找到了一个适用于 UIViewController 的解决方案。

在带有 UITableView 的 UIViewController 中,你应该:

在 viewDidLoad 中设置extendedLayoutIncludesOpaqueBars = true 在故事板中将 tableView 顶部约束到 superview 顶部,常量 = 0(当导航栏为半透明时,tableView 将位于导航栏和状态栏下)

之后,如果你点击状态栏,tableview 会停在正确的位置。

【讨论】:

你检查过 iPhone X 吗?我需要针对安全区域设置 tableView 顶部约束。 @FrédéricAdda 是的,它有效。它也适用于不透明的导航栏(检查我编辑的答案)。为什么需要安全区域的顶部约束? 在我的情况下,我需要拉表视图重新加载。如果我在导航栏中使用“首选大字体”,则 tableView 不会滚动到顶部。如果我使用小字体,那么我没有问题。 @FrédéricAdda 在我的场景中,我也有 UIRefreshControl 并且运行良好。没有代码我帮不了你。还请记住,使用 largeTitle,您需要将 refreshControl 设置为 tableView.refreshControl 而不是 tableView.addSubview(refreshControl) 这段代码似乎可以正常工作,但是如果您不希望 TableView 被限制到 Superview,而是到另一个根据导航栏大小改变位置的 View,您会怎么做?【参考方案4】:

在你的 ViewController 中声明一个 Bool 类型的 var didBeginScrollToTop。 将控制器分配为滚动视图的委托。那么

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

这样做是在弹跳时调整您的内容偏移量。该标志用于捕捉 scrollToTop 手势并在滚动时重置。您也可以在设置 .zero 偏移后将其设置为关闭。如果你有子 VC 的实现,在覆盖这 3 个委托方法时不要忘记调用 super。 现在我的第一个方法是跟踪内容offSet 何时

请注意,您可能还需要处理:Strange velocity prefers large title

【讨论】:

【参考方案5】:

我已经修复它,在滚动到顶部后将 contentOffset 设置为 0。

func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool 
    return true


func scrollViewDidScrollToTop(_ scrollView: UIScrollView) 
    scrollView.contentOffset.y = 0.0

【讨论】:

与我之前看到的所有其他解决方案相比,您的解决方案似乎不那么老套。它运作良好吗?没有动画故障? 这并不理想,但可以工作。我的意思是在动画停止后一切正常,但是动画不是那么快,所以可以看出有些东西很丑。 这很笨拙。整整一秒钟后,它突然回弹并折叠我的搜索控制器搜索栏。 (iOS 13 Xcode 11.1)。不能推荐这个

以上是关于使用大标题时 iOS 11 滚动到顶部无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

带有导航栏大标题的 UITableView 奇怪的滚动行为,顶部的弹跳效果在滚动到顶部时自动切断/生涩

如何在 iOS 11 中像点击状态栏一样调用缓慢滚动到顶部的动画?

再次滚动到顶部时的 TwoWayView 空白问题

切换到 iOS 7 后 UITableView 不滚动

按下窗口上部时防止Ios设备滚动到顶部

使用 ui-router 和 Angularjs 自动滚动到顶部