首先,构造属性字符串,保存交互文本的范围和文本本身。
然后,用CoreText框架绘制属性字符串,保留CTFrameRef。
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, bounds);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
CFRelease(framesetter);
CTFrameDraw(frame, context);
//CFRelease(frame);
CGPathRelease(path);
最后,像这样覆盖 [view touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event]:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
if ([allTouches count] == 1) {
UITouch *touch = (UITouch *)[allTouches anyObject];
CGPoint touchPoint = [touch locationInView:self];
// Convert to coordinate system of current view
touchPoint.y -= self.bounds.size.height;
touchPoint.y *= -1;
CGPathRef statusPath = CTFrameGetPath(statusCTFrame);
NSString *touchedInterStr = nil;
if (CGPathContainsPoint(statusPath, NULL, touchPoint, FALSE)) {
touchedInterStr = [self getInteractiveStringInFrame:statusCTFrame atPosition:touchPoint];
} else {
return ;
}
}
}
- (NSString *)getInteractiveStringInFrame:(CTFrameRef)frame atPosition:(CGPoint)point
{
CGPathRef path = CTFrameGetPath(frame);
CGRect rect;
CGPathIsRect(path, &rect);
// Convert point into rect of current frame, to accurately perform hit testing on CTLine
CGPoint pointInsideRect = point;
pointInsideRect.x = point.x - rect.origin.x;
CFArrayRef lines = CTFrameGetLines(statusCTFrame);
CFIndex count = CFArrayGetCount(lines);
CGFloat curUpBound = rect.origin.y + rect.size.height;
CFIndex touchedIndex = -1;
for (CFIndex pos = 0; pos < count; pos++) {
CTLineRef curLine = CFArrayGetValueAtIndex(lines, pos);
CGFloat ascent, descent, leading;
CTLineGetTypographicBounds(curLine, &ascent, &descent, &leading);
CGFloat curHeight = ascent + descent + leading;
if (pointInsideRect.y >= curUpBound-curHeight && pointInsideRect.y <= curUpBound){
touchedIndex = CTLineGetStringIndexForPosition(curLine, pointInsideRect); // Hit testing
break;
}
curUpBound -= curHeight;
}
if (touchedIndex == -1)
return nil;
NSEnumerator *enumerator = [interactiveStrs objectEnumerator];
InteractiveString *curString;
while ((curString = (InteractiveString *)[enumerator nextObject])) {
if (NSLocationInRange(touchedIndex, curString.range)) {
return curString.content;
}
}
return nil;
}
您在 touchesEnded 中获得交互式文本,然后您可以做任何您想做的事情,例如触发委托方法。
PS:这个是老套的方案,听说iOS5提供了一个增强的UIWebView之类的东西来实现需求,也许你可以查看apple sdk文档库。