用奇怪的 contentOffsetY 调用 scrollViewDidScroll

Posted

技术标签:

【中文标题】用奇怪的 contentOffsetY 调用 scrollViewDidScroll【英文标题】:scrollViewDidScroll called with strange contentOffsetY 【发布时间】:2019-03-23 15:22:38 【问题描述】:

我有一个UIViewController,其中包含一个NSFetchedResultsController。在将行插入顶部之后,我想保持这些行在插入之前的位置可见。这意味着我需要进行一些计算以在更新后立即保留 contentOffSetY。计算是正确的,但我注意到 scrollViewDidScroll 在滚动到我指定的 contentOffsetY 后被调用,这导致状态损坏。这是日志记录:

Will apply an corrected Y value of: 207.27359771728516
Scrolled to: 207.5
Corrected to: 207.27359771728516
Scrolled to: 79.5 <-- Why is this logline here?

您可以直接克隆一个示例项目:https://github.com/Jasperav/FetchResultControllerGlitch(提交https://github.com/Jasperav/FetchResultControllerGlitch/commit/d46054040139afeeb648e1e0b5b113bd98685b4a,该项目的最新版本只有小故障,对scrollViewDidScroll方法的奇怪调用现在已经消失了。如果你修复了我奖励的故障赏金。只需克隆最新版本,运行它并滚动一点。你会看到奇怪的内容偏移(故障))。运行项目,你会看到奇怪的输出。这是controllerDidChangeContent 方法:

public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    let currentSize = tableView.contentSize.height

    UIView.performWithoutAnimation 
        tableView.endUpdates()

        let newSize = tableView.contentSize.height
        let correctedY = tableView.contentOffset.y + newSize - currentSize

        print("Will apply an corrected Y value of: \(correctedY)")
        tableView.setContentOffset(CGPoint(x: 0,
                                           y: correctedY),
                                   animated: false)
        print("Corrected to: \(correctedY)")
    

如果我在tableView.endUpdates() 之后立即调用tableView.layoutIfNeeded,则代表已被调用。调用委托方法的原因是什么?有什么办法不滚动吗?

【问题讨论】:

尝试打开雷达。检查您的项目并且私有函数调用setContentOffset 方法。如果你不需要调用堆栈,我可以分享给你 @JoshuaFrancisRoman 我更改了一些文件,现在它只有一点点故障,但这确实需要修复。您可以检查最新版本,滚动一点并等待它出现故障吗?好烦人…… 【参考方案1】:

我下载了您的代码并进行了一些调整以解决故障问题。这是我所做的。

    将表格视图的estimatedRowHeight 属性设置为某个数字
    init() 
        super.init(frame: .zero, style: .plain)
        estimatedRowHeight = 50.0
        register(MyTableViewCell.self, forCellReuseIdentifier: "cell")
    
    创建了一个函数来处理 UITableView 重新加载操作而不修改当前 contentOffset
    func reloadDataWithoutScroll() 
        let lastScrollOffset = contentOffset
        beginUpdates()
        reloadData()
        layoutIfNeeded()
        endUpdates()
        layer.removeAllAnimations()
        setContentOffset(lastScrollOffset, animated: false)
    
    更新了controllerDidChangeContent 函数以使用reloadDataWithoutScroll 函数
    UIView.performWithoutAnimation 
        tableView.performBatchUpdates(
            tableView.insertRows(at: inserts, with: .automatic)
        )   
        inserts.removeAll()
        tableView.reloadDataWithoutScroll()
    

当我执行这些更改时,添加新行时它不会滚动。但是,当当前 contentOffset 为 0 时,它会滚动显示新添加的行。从逻辑上讲,我认为这不是问题。

【讨论】:

以上是关于用奇怪的 contentOffsetY 调用 scrollViewDidScroll的主要内容,如果未能解决你的问题,请参考以下文章

关于 Java 的 Scanner类!!!!

调用 sc.parallelize() 时出现 WindowsError

TP框架 MODEL类和命名空间

tp框架之Model类与命名空间

tp框架之Model类与命名空间

函数体调用C ++末尾的奇怪循环