UITableView 在 reloadData 后自动向下滚动

Posted

技术标签:

【中文标题】UITableView 在 reloadData 后自动向下滚动【英文标题】:UITableView automatically scrolls down after a reloadData 【发布时间】:2012-04-06 18:12:04 【问题描述】:

我的 iPad 应用程序(OS X 10.7.3、Xcode 4.3.2)中有一个表格视图会自动向下滚动一点,但不知道在哪里寻找原因。情况如下:

UITableView 填满整个屏幕,大部分单元格都是固定高度的单元格。一个例外是包含 UITextView 的单元格,并且具有动态高度(或者换句话说,单元格的高度会调整以适应文本量)。

如果表格碰巧在表格视图位于顶部时切断了动态高度单元格,则问题会出现。当视图首次加载时,表格正常绘制,只有部分 UITextView 单元格可见。但是,如果我显示一个 UIPopoverController,我需要在弹出框被解除后执行 reloadData,当我这样做时,表格视图将向下滚动以显示所有 UITextView。 (注意不是包含 UITextView 的单元格,只是 UITextView。该表格是一个分组表格,并且 UITextView 单元格是该部分中唯一的单元格,因此在此幻像滚动后圆角底部边缘仍然不可见。)

我在我的应用中看不到任何滚动表格视图或设置内容偏移的代码,所以我完全不知道是什么原因造成的。

为了尝试缩小范围,我将视图设置为支持 UIScrollViewDelegate,如果我在 scrollViewDidScroll: 方法中放置一个断点,程序实际上会在弹出框消失后停止并给我以下回溯:

(lldb) bt
* thread #1: tid = 0x1f03, 0x0005245f MyApp`-[ContactDisplayViewController scrollViewDidScroll:] + 31 at ContactDisplayViewController.m:1143, stop reason = breakpoint 3.1
    frame #0: 0x0005245f MyApp`-[ContactDisplayViewController scrollViewDidScroll:] + 31 at ContactDisplayViewController.m:1143
    frame #1: 0x017e3494 UIKit`-[UIScrollView setContentOffset:] + 521
    frame #2: 0x0180804d UIKit`-[UITableView setContentOffset:] + 334
    frame #3: 0x017d495e UIKit`-[UIScrollViewScrollAnimation setProgress:] + 523
    frame #4: 0x0183d234 UIKit`-[UIAnimator(Static) _advance:] + 255
    frame #5: 0x02c013a3 GraphicsServices`HeartbeatTimerCallback + 35
    frame #6: 0x023278c3 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
    frame #7: 0x02328e74 CoreFoundation`__CFRunLoopDoTimer + 1220
    frame #8: 0x022852c9 CoreFoundation`__CFRunLoopRun + 1817
    frame #9: 0x02284840 CoreFoundation`CFRunLoopRunSpecific + 208
    frame #10: 0x02284761 CoreFoundation`CFRunLoopRunInMode + 97
    frame #11: 0x02bfe1c4 GraphicsServices`GSEventRunModal + 217
    frame #12: 0x02bfe289 GraphicsServices`GSEventRun + 115
    frame #13: 0x017a4c93 UIKit`UIApplicationMain + 1160
    frame #14: 0x0000263d MyApp`main + 125 at main.m:14

如果我在该方法中打印出 scrollView,则表明 UITableView 处于运动状态(不确定 contentOffset 来自何处):

Printing description of scrollView:
<UITableView: 0xc3ed400; frame = (0 99; 383 817); clipsToBounds = YES; 
autoresize = W+RM+H; layer = <CALayer: 0x7bf1a40>; contentOffset: 0, 14>

这种幻象滚动显示在设备和模拟器上,以及 ios 4.3、5.0 和 5.1 中。有人有什么想法吗?

【问题讨论】:

我模糊记得以前听说过这件事。由于 UITableViews 是 UIScrollView 的子类,UITextViews 也是如此,所以它可能会变得混乱。猜测也许尝试在重新加载之前更改 TextView 上的某些属性,例如禁用滚动? 你是对的,在 reloadData 之前禁用文本视图的滚动确实可以防止幻像滚动发生。如果您发表评论作为答案,我会接受。谢谢。 【参考方案1】:

我模糊记得以前听说过这件事。由于UITableViews 是UIScrollView 的子类,UITextViews 也是如此,所以它可能会变得混乱。

猜测也许尝试在重新加载之前更改 TextView 上的某些属性,例如禁用滚动?

[myTextView setScrollEnabled:NO];

【讨论】:

【参考方案2】:

当 UITextView 变为FirstResponder 时(我相信从 iOS 3 开始),如果它位于 UIScrollView/UITableViewController 内,iOS 将自动滚动该滚动视图以确保 UITextView 可见。

有关解决方法,请查看:Disable UIScrollView scrolling when UITextField becomes first responder

【讨论】:

【参考方案3】:

我继承了 UIScrollView 子类(在我的例子中是子类 UITextField)并确保我不接受“任意”内容偏移:

override var contentOffset: CGPoint 
    set 
        let maxContentOffsetY = max(self.contentSize.height - self.frame.size.height, 0.0)
        super.contentOffset.y = min(newValue.y, maxContentOffsetY)
    
    get 
        return super.contentOffset
    

【讨论】:

以上是关于UITableView 在 reloadData 后自动向下滚动的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableView 上延迟 reloadData

iOS UITableView reloadData 刷新结束后执行后续操作

UITableView 没有在 reloadData 上重新加载

ReloadData (UITableView) 不起作用

UITableView 在 reloadData 后自动向下滚动

UITableView 奇怪的 reloadData 问题