Add tap event to IOS NSMutableAttributedString

醉酒当歌 提交于 2020-01-11 03:58:10

问题


I have an NSMutableAttributedString such as "Bob liked your picture".

I'm wondering if I can add two different tap events to "Bob" and "picture". Ideally, tapping "Bob" would present a new view controller with Bob's profile and tapping "picture" would present a new view controller with the picture. Can I do this with NSMutableAttributedString?


回答1:


The way I would handle it is using a standard NSString in a UITextView. Then taking advantage of the UITextInput protocol method firstRectForRange:. Then you could easily overlay an invisible UIButton in that rect and handle the action you'd like to take.




回答2:


You can achieve this by using CoreText to implement a method that will retrieve the index of the character the user selected / touched. First, using CoreText, draw your attributed string in a custom UIView sub class. An example overridden drawRect: method:

- (void) drawRect:(CGRect)rect
{
    // Flip the coordinate system as CoreText's origin starts in the lower left corner
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0.0f, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0f, -1.0f);

    UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge   CFAttributedStringRef)(_attributedString));

    if(textFrame != nil) {
        CFRelease(textFrame);
    }

    // Keep the text frame around.
    textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path.CGPath, NULL);
    CFRetain(textFrame);

    CTFrameDraw(textFrame, context);
}

Secondly, create a method that interrogates the text to find the character index for a given point:

- (int) indexAtPoint:(CGPoint)point
{
    // Flip the point because the coordinate system is flipped.
    point = CGPointMake(point.x, CGRectGetMaxY(self.bounds) - point.y);
    NSArray *lines = (__bridge NSArray *) (CTFrameGetLines(textFrame));

    CGPoint origins[lines.count];
    CTFrameGetLineOrigins(textFrame, CFRangeMake(0, lines.count), origins);

    for(int i = 0; i < lines.count; i++) {
        if(point.y > origins[i].y) {
            CTLineRef line = (__bridge CTLineRef)([lines objectAtIndex:i]);
            return CTLineGetStringIndexForPosition(line, point);
        }
    }

    return 0;
}

Lastly, you can override the touchesBegan:withEvent: method to get the location of where the user touched and convert that into a character index or range:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *t = [touches anyObject];
    CGPoint tp = [t locationInView:self];
    int index = [self indexAtPoint:tp];

    NSLog(@"Character touched : %d", index);
}

Be sure to include CoreText into your project and clean up any resources (like text frames) you keep around as that memory is not managed by ARC.



来源:https://stackoverflow.com/questions/15483697/add-tap-event-to-ios-nsmutableattributedstring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!