【问题标题】:Scroll text to specific point in UITextView depending on font size根据字体大小将文本滚动到 UITextView 中的特定点
【发布时间】:2018-08-29 15:04:26
【问题描述】:

当用户按下文本视图本身之外的按钮时(在 iOS 上),我希望我的 UITextView 滚动到特定点(一个单词,或者更好的断点:>>>“)。字体大小可能因用户交互而异(即用户可以增大或减小字体大小)。文本本身由用户粘贴(他们以交互方式添加断点)。

我试图通过获取断点 (">>>") 的 y 位置(以像素为单位)然后根据(使用 setContentOffset)设置 textView 的偏移量来实现这一点。

问题是我得到的y点是错误的!

这是我的代码的一个 sn-p(仅适用于 >>>“重复出现的一个):

NSRange range = [self.textview.text rangeOfString:@">>>"];

UITextPosition *beginning = self.textview.beginningOfDocument;
UITextPosition *start = [self.textview positionFromPosition:beginning offset:range.location];
UITextPosition *end = [self.textview positionFromPosition:start offset:range.length];
UITextRange *textRange = [self.textview textRangeFromPosition:start toPosition:end];
CGRect rect = [self.textview firstRectForRange:textRange];

[self.textview setContentOffset:CGPointMake(0, rect.origin.y)];

我的方法有什么问题?我觉得有更好(更简单)的方法来做同样的事情......

PS:我找到了另一个与相同问题相关的主题,但它在 swift 中,我无法翻译:Scroll UITextView to specific text

【问题讨论】:

    标签: ios xcode scroll uitextview nsrange


    【解决方案1】:

    您需要将rect 转换为文本视图坐标空间。

    试试这样:

    // get the range
    NSRange range = [self.textview.text rangeOfString:@">>>"];
    
    // get the rect in the textview's coordinate space
    CGRect foundRect = [self frameOfTextRange:range inTextView:self.textview];
    
    // scroll the found rect into view
    [self.textview setContentOffset:CGPointMake(0.0, foundRect.origin.y) animated:YES];
    

    使用这种方法(在这里找到:https://stackoverflow.com/a/9606413/6257435):

    - (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView
    {
        // ensure textview layouManager has been processed
        [textView.layoutManager ensureLayoutForTextContainer:textView.textContainer];
    
        UITextPosition *beginning = textView.beginningOfDocument;
        UITextPosition *start = [textView positionFromPosition:beginning offset:range.location];
        UITextPosition *end = [textView positionFromPosition:start offset:range.length];
        UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
        CGRect rect = [textView firstRectForRange:textRange];
        return [textView convertRect:rect fromView:textView.textInputView];
    }
    

    当然,您需要添加错误处理(对于未找到的文本等)。

    【讨论】:

    • 好的,如果它在第一行文本中,它适用于第一个 >>>"。如果我有一个很长的文本,比如说,我在它的第 40 行只设置了一个“>>>”,它只会在第三次或第四次尝试时达到目的(我的意思是,按 3 或 4 次按钮触发动作'frameOfTextRange')。每次按下按钮时,通过 NSLog,我得到不同的 foundRect.origin.y 值(7567.000000 / 10591.000000 / 12775.000000)。右边的是最后一个……
    • 好的...如果我将文本视图的大小(以编程方式)调整为 20.000 像素的高度(即超过文本的长度),它会完美工作,但我担心它是“非法的”(将我有记忆问题吗?)。
    • 啊...我们必须确保 textView 的 layoutManager 已经处理了内容。查看我编辑的答案(frameOfTextRange 方法中的第一行)。
    【解决方案2】:

    我迅速尝试了上述事情,并意识到计算矩形然后滚动到该矩形是没有意义的。您只需调用func scrollRangeToVisible(_ range: NSRange) 即可滚动到textView 中的单词。

    let range: Range = self.textView.text.range(of: "amendment")!
    let nsRange = NSRange(range, in: self.textView.text)
    
    self.textView.scrollRangeToVisible(nsRange)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-12
      • 2023-04-02
      • 2014-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多