【问题标题】:ios - how to find what is the visible range of text in UITextView?ios - 如何在 UITextView 中找到可见的文本范围?
【发布时间】:2011-08-29 09:30:03
【问题描述】:

如何在可滚动、不可食用的 UITextView 中找到可见的文本?

例如我可能需要显示下一段,然后我想找到当前可见的文本范围并使用它来计算适当的范围并使用scrollRangeToVisible: 滚动文本视图

【问题讨论】:

    标签: iphone ios uiscrollview uitextview


    【解决方案1】:

    我在这里找到了另一个解决方案。 在我看来,这是解决这个问题的更好方法。 https://stackoverflow.com/a/9283311/889892

    由于 UITextView 是 UIScrollView 的子类,它的 bounds 属性反映了其坐标系的可见部分。所以这样的事情应该可以工作:

    -(NSRange)visibleRangeOfTextView:(UITextView *)textView {
        CGRect bounds = textView.bounds;
        UITextPosition *start = [textView characterRangeAtPoint:bounds.origin].start;
        UITextPosition *end = [textView characterRangeAtPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))].end;
        return NSMakeRange([textView offsetFromPosition:textView.beginningOfDocument toPosition:start],
            [textView offsetFromPosition:start toPosition:end]);
    }
    

    这假定一个从上到下、从左到右的文本布局。如果你想让它适用于其他布局方向,你将不得不更加努力。 :)

    【讨论】:

    • 当你说“这样的东西应该可以工作”时,你真的尝试过吗?这对我来说几乎是实际视觉文本范围的三倍。谢谢。
    【解决方案2】:

    我这样做的方法是计算每个段落的所有大小。用 sizeWithFont:constrainedToSize:lineBreakMode:

    然后,您将能够从 [textView contentOffset] 确定哪个段落是可见的。

    要滚动,不要使用 scrollRangeToVisible,只需使用 setContentOffset:CGPoint y 参数应该是下一段的所有高度大小的总和,或者只是添加 textView.frame.size.height,如果是的话比下一段的开头更接近。

    这有意义吗?

    回答下面的评论请求代码(未经测试):

      CGFloat paragraphOffset[MAX_PARAGRAPHS];
    
        CGSize constraint = CGSizeMake(widthOfTextView, 999999 /*arbitrarily large number*/);
        NSInteger paragraphNo = 0;
        CGFloat offset = 0;
    
        for (NSString* paragraph in paragraphs) {
            paragraphOffset[paragraphNo++] = offset;
            CGSize paragraphSize = [paragraph sizeWithFont:textView.font constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
            offset += paragraphSize.height;
        }   
    
        // find visible paragraph
        NSInteger visibleParagraph = 0;
        while (paragraphOffset[visibleParagraph++] < textView.contentOffset.y);
    
    
        // scroll to paragraph 6
        [textView setContentOffset:CGPointMake(0, paragraphOffset[6]) animated:YES];
    

    【讨论】:

    • 你能给出一些示例代码吗?我不确定 sizeWithFont:constrainedToSize:lineBreakMode: 是如何工作的,什么是 constrainedToSize: 参数?
    • 在上面添加了代码。仅供参考,段落是段落字符串的 NSArray
    • 请注意,您可以将 9999999 替换为 FLT_MAX(大值的默认 iPhone 变量)
    【解决方案3】:

    如果你想要一个 Swift 解决方案,我使用这个:

    斯威夫特 2

    public extension UITextView {
        public var visibleRange: NSRange? {
            if let start = closestPositionToPoint(contentOffset) {
                if let end = characterRangeAtPoint(CGPointMake(contentOffset.x + CGRectGetMaxX(bounds), contentOffset.y + CGRectGetMaxY(bounds)))?.end {
                    return NSMakeRange(offsetFromPosition(beginningOfDocument, toPosition: start), offsetFromPosition(start, toPosition: end))
                }
            }
            return nil
        }
    }
    

    斯威夫特 3

    public extension UITextView {
        public var visibleRange: NSRange? {
            guard let start = closestPosition(to: contentOffset),
                      end = characterRange(at: CGPoint(x: contentOffset.x + bounds.maxX, 
                                                       y: contentOffset.y + bounds.maxY))?.end 
            else { return nil }
            return NSMakeRange(offset(from: beginningOfDocument, to: start), offset(from: start, to: end))
        }
    }
    

    【讨论】:

      【解决方案4】:

      您可以选择使用 UIWebView 而不是 UITextView。然后,您可以使用锚点和 javascript 滚动到文本中的适当位置。您可能可以在每个段落的开头以编程方式插入锚点以使其更容易。

      【讨论】:

      • 我不熟悉javascript和复杂的html东西,你能给我举个例子吗? UIWebView 也可能比 UITextView 更难处理
      • @xlc0212:如果您不需要编辑,使用 UIWebview 将比每次需要滚动时计算 UITextView 的文本大小更容易(并且可能更快)。只需查看“html 锚点”是什么——这并不复杂。
      【解决方案5】:

      基于"Noodle of Death" answer的Swift 3.0/3.1解决方案。

      public extension UITextView {
      
          public var visibleRange: NSRange? {
              if let start = closestPosition(to: contentOffset) {
                  if let end = characterRange(at: CGPoint(x: contentOffset.x + bounds.maxX, y: contentOffset.y + bounds.maxY))?.end {
                      return NSMakeRange(offset(from: beginningOfDocument, to: start), offset(from: start, to: end))
                  }
              }
              return nil
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-06
        • 1970-01-01
        • 1970-01-01
        • 2012-05-03
        • 2012-02-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多