【问题标题】:How to force the layout of glyphs positioned far outside the UITextView's vertical bounds?如何强制位于 UITextView 垂直边界之外的字形布局?
【发布时间】:2019-04-11 17:36:58
【问题描述】:

这里不需要代码。我需要一些关于如何布局一个很长的多行字符串的所有字形的指导,以便在启用滚动的 UITextView 中显示。了解情况的一些背景资料。

背景:我有一个很长的多字符串文本,需要在启用滚动的 UITextView 中显示。我创建了一个函数,用于识别多行字符串中搜索字符串匹配的CGRect 位置,然后将用户动画到匹配的CGRect 位置。这是通过将匹配文本的CGRect 传递给contentOffset 来实现的,该contentOffset 将滚动到该位置。传递给contentOffsetCGRect 是使用layoutmanager 生成的,以确保准确性。换句话说,文本的CGRect 是基于匹配字符串字形的位置。

但是,如果匹配的搜索字符串的CGRect 垂直定位远离 UITextView bounds.height,则动画实际上会失败。没有任何滚动。就好像滚动动画不知道在哪里找到CGRect 位置来滚动到匹配的字符串一样。如果我首先手动滚动到 UITextView 的最底部,然后将动画执行到匹配的搜索字符串的CGRect 位置,我可以纠正这个问题。在这种情况下,UITextView就好像拥有了一个完整的文本布局图,可以准确的找到匹配的搜索字符串CGRect在多行字符串中的位置。

基于上述,我很明显 UITextView 不会一次布局多行字符串的所有字形。该视图可能会以类似于表格视图创建单元格的方式绘制块中的字形。在我看来,当我手动滚动视图边界到内容垂直大小的最底部时,UITextView 能够保留所有字形布局信息。

是否有任何代码可以有效地布置 UITextView 的整个内容大小,即使字形远远超出 UITextView 的垂直边界?看来我需要先布局所有字形以防止出现上述错误。

【问题讨论】:

  • UITextViewscrollRangeToVisible 方法有什么问题?
  • Rob - 是的,scrollRangeToVisible 知道在哪里可以找到匹配项。但是,该函数具有与我运行的动画冲突的固有动画。我可以禁用 scrollRangeToVisible 的固有动画。有一个问题:我的动画序列还使用了一个子视图,一个带有匹配文本大小的边框的矩形。子视图使用滚动进行动画处理,并将匹配的文本圈起来以作为视觉提示。子视图使用字形的 CGRect。子视图也会丢失。 scrollRangeToVisible 不提供将子视图定位到正确位置的解决方案。
  • 在尝试滚动之前,您是否检查过文本视图的contentSize 是否足够大以包含您的CGRect?如果您在文本视图的控制之外触发额外的增量布局,contentSize 可能没有正确更新。
  • 不是直接的。我确实检查了最后一个匹配的矩形(我通过匹配数组递增)是否位于 textview 的范围内。如果为 false,则用户可以通过按下启动上述动画序列的按钮来递增匹配数组。简而言之,除非匹配位于 textview 的边界之外,否则动画不可用。当匹配的文本与 textview 的边界距离很大时,就会发生错误。
  • Rob- 当我想到你的建议时,每当我访问contenSize 时,我都会在动画触发之前获得完整的尺寸。必须有一些可以更新的对象以提供所需的布局信息。 scrollRangeToVisible 是如何完成任务的?

标签: swift uiscrollview uitextview cgrect


【解决方案1】:

出于性能原因,UITextView 的整个内容布局不一定在您预期的时候确定。

例如,如果文本视图中有足够的文本跨越可见区域的 10 倍,UIKit 可能会“推迟”布置文本。毕竟,仅仅因为文本在那里并不意味着用户会滚动到它。

NSLayoutManager 提供了几个功能,可让您确保在您想要访问文本视图时已将其全部内容布局好(请参阅https://developer.apple.com/documentation/uikit/nslayoutmanager):

func ensureGlyphs(forCharacterRange: NSRange)
func ensureGlyphs(forGlyphRange: NSRange)
func ensureLayout(forBoundingRect: CGRect, in: NSTextContainer)
func ensureLayout(forCharacterRange: NSRange)
func ensureLayout(forGlyphRange: NSRange)
func ensureLayout(for: NSTextContainer)

根据 OP 的 cmets,在 viewDidLayoutSubviews() 中调用 .ensureLayout 解决了这个问题。

【讨论】:

  • DonMag... 非常感谢您花时间考虑此事。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-09
  • 2014-07-09
  • 2016-06-05
  • 1970-01-01
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
相关资源
最近更新 更多