LayoutManager boundingRectForGlyphRange用于多行文本

时间:2014-10-31 13:06:08

标签: ios objective-c layout-manager

我有一个文本,它在屏幕上显示如下:

#first SomePersonFirstName
SomePersonLastName #secondTag

在我的应用程序中,我保留了有关此文本的3个标签及其范围的信息,其中包括:

  1. 第一

  2. SomePersonFirstName SomePersonLastName
  3. secondTag

  4. 现在我将它显示给用户之后我想要检测哪一个被点击了,所以我遍历所有的信息,为每个信息获取boundingRectForGlyphRange,并检查这个矩形是否包含一个点点击了。

    一切都在运作,但是我遇到了一个奇怪的情况,这让我对如何做到了这一点。 问题是这些标签的边界反应重叠。

    enter image description here

    因为person标签被分成2行,所以绑定的rects从0,0开始并覆盖#first bounding rect。

    问题是当你点击这个冲突区域时,无法确定哪一个被点击了。

    我实际上不知道如何处理。有没有其他方法来检测边界矩形,但实际上不会绑定到空白区域,这只会覆盖文本本身?

    修改

    我正在使用的代码:

    - (CGRect)boundingRectForCharacterRange:(NSRange)range
    {
        NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.labelTitle.attributedText];
        NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
        [textStorage addLayoutManager:layoutManager];
        NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(self.labelTitle.bounds.size.width, CGFLOAT_MAX)];
        textContainer.lineFragmentPadding = 0;
        textContainer.lineBreakMode = self.labelTitle.lineBreakMode;
        [layoutManager addTextContainer:textContainer];
    
        NSRange glyphRange;
        [layoutManager characterRangeForGlyphRange:range actualGlyphRange:&glyphRange];
        return [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer];
    }
    
    -(void)tapped:(UIGestureRecognizer *)recognizer
    {
        UILabel *label = (UILabel *)recognizer.view;
        CGPoint location = [recognizer locationInView:label];
    
        CommentTag* selectedCommentTag = nil;
        for (CommentTag* commentTag in self.comment.tags)
        {
            CGRect commentRect = [self boundingRectForCharacterRange:[commentTag tagRange]];
            if(CGRectContainsPoint(commentRect, location))
            {
                if(selectedCommentTag == nil)
                {
                    selectedCommentTag = commentTag;
                }
                else
                {
                    if(selectedCommentTag.offset > commentTag.offset)
                    {
                        selectedCommentTag = commentTag;
                    }
                }
            }
        }
    
        if(selectedCommentTag)
        {
            if([selectedCommentTag.type isEqualToString:COMMENTTAG_TYPE_TAG])
            {
                NSLog(@"%@", [selectedCommentTag value]);
            }
        }
    }
    

    这里我只是将第一个标签放在左边,但这并没有解决我的例子中#secondTag的问题

1 个答案:

答案 0 :(得分:2)

当两个边界反复重叠时,有两(3)个实例:

  1. 两个范围重叠索引值。
  2. 其中一个边界占据多行。
  3. 两个边界都占据多行。
  4. 对于(1),当您接受点击普通字形时,您只需要制定自己的一套规则。

    对于(2),总是更喜欢只跨越一条线的范围 - 你可以通过比较矩形高度来判断。

    对于(3),你必须遍历这些行。

    或者,您是否考虑过相反的方法?

    NSRange characterRange = [layoutManager glyphRangeForBoundingRect:CGRectMake(point.x, point.y, 1, 1) inTextContainer:container];
    if (NSLocationInRange(characterRange.location, firstRange) {
      // ...
    } else if (NSLocationInRange(characterRange.location, secondRange) {
      // ...
    } // etc...
    

    通过将您的触摸点转换为尺寸为CGRect的{​​{1}},您可以让1x1为您提供layoutManager长度{{} 1}}表示触摸点处的单个字形。使用此NSRange 1,您可以与NSRange列表进行比较,看看您点击了哪一个。使用你的来源:

    location