-
-
Save nickhsu/73166d4e94179ce7ec97e8c8312c41d7 to your computer and use it in GitHub Desktop.
Detect a tap on a URL inside a UITextView.Note: the rs_links method isn't included -- you'll need something that takes text and returns an array of detected links. This gist just demonstrates walking through the UITextView characters.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "UITextView+RSExtras.h" | |
@implementation UITextView (RSExtras) | |
static BOOL stringCharacterIsAllowedAsPartOfLink(NSString *s) { | |
/*[s length] is assumed to be 0 or 1. s may be nil. | |
Totally not a strict check.*/ | |
if (s == nil || [s length] < 1) { | |
return NO; | |
} | |
unichar ch = [s characterAtIndex:0]; | |
return ![[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:ch]; | |
} | |
- (NSString *)rs_potentialLinkAtPoint:(CGPoint)point { | |
/*Grow a string around the tap until hitting a space, cr, lf, or beginning or end of document.*/ | |
/*If we don't check for end of document, then you could tap way below end of text, and it would return a link if the last text was a link. This has the unfortunate side effect that you can't tap on the last character of a link if it appears at the end of a document. I can live with shipping that.*/ | |
UITextRange *textRange = [self characterRangeAtPoint:point]; | |
UITextPosition *endOfDocumentTextPosition = self.endOfDocument; | |
if ([textRange.end isEqual:endOfDocumentTextPosition]) | |
return nil; | |
UITextPosition *tapPosition = [self closestPositionToPoint:point]; | |
if (tapPosition == nil) | |
return nil; | |
NSMutableString *s = [NSMutableString stringWithString:@""]; | |
/*Move right*/ | |
UITextPosition *textPosition = tapPosition; | |
BOOL isFirstCharacter = YES; | |
while (true) { | |
UITextRange *rangeOfCharacter = | |
[self.tokenizer rangeEnclosingPosition:textPosition withGranularity:UITextGranularityCharacter inDirection:UITextWritingDirectionNatural]; | |
NSString *oneCharacter = [self textInRange:rangeOfCharacter]; | |
if (isFirstCharacter) { | |
/*If first character is cr or lf, then we're off the right hand side of the link. Maybe way outside.*/ | |
if ([oneCharacter isEqualToString:@"\n"] || [oneCharacter isEqualToString:@"\r"]) | |
return nil; | |
} | |
isFirstCharacter = NO; | |
if (!stringCharacterIsAllowedAsPartOfLink(oneCharacter)) | |
break; | |
[s appendString:oneCharacter]; | |
textPosition = [self positionFromPosition:textPosition offset:1]; | |
if (textPosition == nil) | |
break; | |
} | |
/*Move left*/ | |
textPosition = [self positionFromPosition:tapPosition offset:-1]; | |
if (textPosition != nil) { | |
while (true) { | |
UITextRange *rangeOfCharacter = | |
[self.tokenizer rangeEnclosingPosition:textPosition withGranularity:UITextGranularityCharacter inDirection:UITextWritingDirectionNatural]; | |
NSString *oneCharacter = [self textInRange:rangeOfCharacter]; | |
if (!stringCharacterIsAllowedAsPartOfLink(oneCharacter)) | |
break; | |
[s insertString:oneCharacter atIndex:0]; | |
textPosition = [self positionFromPosition:textPosition offset:-1]; | |
if (textPosition == nil) | |
break; | |
} | |
} | |
return s; | |
} | |
- (NSArray *)rs_links:(NSString *)string { | |
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink | |
error:nil]; | |
return [detector matchesInString:string | |
options:0 | |
range:NSMakeRange(0, [string length])]; | |
} | |
- (NSString *)rs_linkAtPoint:(CGPoint)point { | |
NSString *potentialLink = [self rs_potentialLinkAtPoint:point]; | |
if (potentialLink == nil || [potentialLink length] < 1) { | |
return nil; | |
} | |
NSArray *links = [self rs_links: potentialLink]; | |
if (links == nil || [links count] < 1) { | |
return nil; | |
} else { | |
return links[0]; | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment