【发布时间】:2014-02-08 20:04:56
【问题描述】:
我一直在为 iOS 7 重新编写我的应用程序。它现在使用新的 TextKit API。我几乎完成了,但自从我开始进行过渡以来,还有一个问题一直让我头疼。
问题: 当我在 UITextView 中输入文本时,有时视图会向上滚动隐藏光标。很难确定模式,但它似乎发生在我删除一行并且下面的文本必须向上移动之后。但只有第二次我删除了一行,并且只删除了文档中的某些行(通常只有换行符但并不总是......)
我已经尝试在 stackoverflow 上使用这些解决方案:
How to stop UITextView from scrolling up when entering it
UITextView keep scrolling after every new line is inserted, so the lines are invisible (iPhone OS)
Scroll to bottom of UITextView erratic in iOS 7
当 UITextView 中有 UITableView 时,还有许多其他问题导致滚动无法正常工作。我的视图中没有表视图。
我想指出,我已将 UITextView 子类化,并发现它肯定是 iOS 7 发出的调用,不仅是向上滚动视图。此外,更奇怪的是,当您按下返回按钮(从 UITextView 中删除一个字符)时,它会向textViewDidChangeSelection: 发送两条消息。这是发生问题时的调用堆栈。 (当问题没有发生时,我仍然会接到两次委托textViewDidChangeSelection:... 这似乎是正常的):
- UITextView 委托
textViewDidChangeSelection:包含要删除的字符的位置,长度为一。 (即 1050,1) - UITextView 委托
textViewDidChangeSelection:再次被调用并包含相同的位置但长度为零。 (即 1050,0) - scrollViewDidScroll(最多 3 次。但一般只有一次)
- 然后 iOS 7 调用
UITextView.scrollRangeToVisible:,第一个调用的范围为 {1050,1}。这对我来说毫无意义。我知道这是在内部调用的,而不是从我的任何代码中调用的,因为这个内部 API 被称为_ensureselectionvisible,没有任何回溯到我可能用来调用滚动事件的函数。
大概前两个调用只是选择字符,然后在内部调用 deleteBackwards。这就说得通了。不过在那之后我就瞎了。我不知道它为什么会滚动或为什么会调用 scrollRangeToVisible: 带错误的范围。
当用户正在编辑文本时,我可以通过在不调用 [super scrollRangeToVisible] 的情况下返回而不调用 UITextView.scrollRangeToVisible:,从而在一定程度上缓解这个问题。我通过覆盖一些滚动视图委托调用并设置一个表示不能滚动的标志来做到这一点。对我来说,这是一个巨大的 UGLY hack,并且在某些情况下仍然会出现问题 - 例如当我在第一次编辑时点击视图时,有时当滚动视图停止减速时。
简而言之,发生的事情是发生了滚动事件(可能是由于上一行向上移动)并且 iOS 出于某种原因认为光标不在视图中。更奇怪的是,即使提供了错误的范围,它确实提供了正确的位置,从而将其滚动到视图中的错误位置。更奇怪的是,它只发生在某些条件下,并且只发生在该条件发生的第二种情况下。我唯一能想到的是,删除文本后 UITextView 的高度计算不正确,它认为文本的位置与实际位置不同。
提前致谢!
更新:
我设置了我之前在scrollViewDidScroll: 中提到的标志,它不会阻止在其他一些情况下的跳跃。但是,仍然存在向后删除文本仍然会跳过屏幕的情况。在视图仍然跳转的情况下,更奇怪的是我看到我正在阻止 [super scrollRangeToVisible] 被调用!因此,内部发生了一些事情,此外,这导致视图滚动。
更新:
它似乎在 613 点和 670 点之间向上跳跃。我不确定是什么导致了分数的差异。它跳跃的行数也不同。我怀疑 something 在条件之间必须相似。此外,当scrollViewDidScroll: 被调用时,我验证了此调用与委托textViewDidChangeSelection: 调用之间的textView.selectedRange.location 相同。
【问题讨论】:
标签: ios objective-c uitextview uitextviewdelegate