Agregar evento de toque a IOS NSMutableAttributedString

Tengo un NSMutableAttributedString como "Bob me gustó tu image".

Me pregunto si puedo agregar dos events de toque diferentes a "Bob" y "image". Idealmente, al tocar "Bob" se presentaría un nuevo controller de vista con el perfil de Bob y al tocar "image" se presentaría un nuevo controller de vista con la image. ¿Puedo hacer esto con NSMutableAttributedString?

La forma en que lo haría sería usar un NSString estándar en una UITextView . Luego, aprovechando el método de protocolo firstRectForRange: Entonces podrías fácilmente superponer un UIButton invisible en ese rectángulo y manejar la acción que te gustaría tomar.

Puede lograr esto mediante el uso de CoreText para implementar un método que recupere el índice del carácter que el usuario seleccionó / ​​tocó. Primero, usando CoreText, dibuja tu cadena atribuida en una UIView personalizada. Un ejemplo anulado drawRect: método:

 - (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); } 

En segundo lugar, cree un método que interroga el text para encontrar el índice de caracteres para un punto dado:

 - (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; } 

Por último, puede anular los touchesBegan:withEvent: método para get la location de donde el usuario tocó y convertirlo en un índice o range de caracteres:

 - (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); } 

Asegúrese de include CoreText en su proyecto y limpie todos los resources (como los frameworks de text) que guarda a medida que ARC no administra esa memory.