4

I been trying to use AsyncDisplayKit framework , I have an requirement to detect url's in text.

I have used ASTextNode but couldn't find any api to detect links.

I read that there is property linkAttributeNames used for url detection but unable to find any example how to do it.

Could someone help me how to use the above class?

thanks

Mukesh
  • 3,680
  • 1
  • 15
  • 32

2 Answers2

7

For Swift 3.0

func addLinkDetection(_ text: String, highLightColor: UIColor, delegate: ASTextNodeDelegate) {
    self.isUserInteractionEnabled = true
    self.delegate = delegate

    let types: NSTextCheckingResult.CheckingType = [.link]
    let detector = try? NSDataDetector(types: types.rawValue)
    let range = NSMakeRange(0, text.characters.count)
    if let attributedText = self.attributedText {
        let mutableString = NSMutableAttributedString()
        mutableString.append(attributedText)
        detector?.enumerateMatches(in: text, range: range) {
            (result, _, _) in
            if let fixedRange = result?.range {
                mutableString.addAttribute(NSUnderlineColorAttributeName, value: highLightColor, range: fixedRange)
                mutableString.addAttribute(NSLinkAttributeName, value: result?.url, range: fixedRange)
                mutableString.addAttribute(NSForegroundColorAttributeName, value: highLightColor, range: fixedRange)

            }
        }
        self.attributedText = mutableString
    }        
}

Add the delegate to your viewController:

/// Delegate function for linkDetection
func textNode(_ textNode: ASTextNode, shouldHighlightLinkAttribute attribute: String, value: Any, at point: CGPoint) -> Bool {
    return true
}

func textNode(_ textNode: ASTextNode, tappedLinkAttribute attribute: String, value: Any, at point: CGPoint, textRange: NSRange) {
    guard let url = value as? URL else { return }
 }
Bas
  • 780
  • 5
  • 17
2

For link detection you need to use external library. I'd recommend https://github.com/twitter/twitter-text You can install it with cocoapods.

Then you need to convert TwitterTextEntity* to NSTextCheckingResult*.

You can use this category of NSString:

- (NSArray <NSTextCheckingResult *>*)textCheckingResultsForURLs {
    NSArray *twitterEntitiesArray = [TwitterText URLsInText:self];
    NSMutableArray *textCheckingResultsArray = [[NSMutableArray alloc] initWithCapacity:[twitterEntitiesArray count]];

    for (TwitterTextEntity *twitterTextEntity in twitterEntitiesArray) {
        NSString *textCheckingResultUTF8 = [[self substringWithRange:twitterTextEntity.range] stringPercentEncode];

        NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@", textCheckingResultUTF8]];

        NSTextCheckingResult *result = [NSTextCheckingResult linkCheckingResultWithRange:twitterTextEntity.range URL:url];
        [textCheckingResultsArray addObject:result];
    }

    return textCheckingResultsArray;
}

Use it like this:

NSArray *links = [yourString textCheckingResultsForURLs];

Then you need to add calculated ranges to NSMutableAttributedString like this:

for (NSTextCheckingResult *textCheckingResult in links) {

        NSMutableDictionary *linkAttributes = [[NSMutableDictionary alloc] initWithDictionary:@{NSForegroundColorAttributeName : [UIColor whiteColor]}];

        linkAttributes[@"TextLinkAttributeNameURL"] = [NSURL URLWithString:textCheckingResult.URL.absoluteString];

        [string addAttributes:linkAttributes range:textCheckingResult.range];
    }

Then you need to configure ASTextNode node to highlight specific ranges. So in parent node add:

_textLabelNode.delegate = self;
_textLabelNode.userInteractionEnabled = YES;
_textLabelNode.linkAttributeNames = @[@"TextLinkAttributeNameURL"];

+

- (void)didLoad {
    // For text node
    self.layer.as_allowsHighlightDrawing = YES;

    [super didLoad];
}

#pragma mark - ASTextNodeDelegate

- (BOOL)textNode:(ASTextNode *)richTextNode shouldHighlightLinkAttribute:(NSString *)attribute value:(id)value atPoint:(CGPoint)point {
    return YES;
}

- (void)textNode:(ASTextNode *)richTextNode tappedLinkAttribute:(NSString *)attribute value:(NSURL *)URL atPoint:(CGPoint)point textRange:(NSRange)textRange {
NSLog(@"TODO");
}

This works for me. Hope, didn't forget about anything.

konradholub
  • 133
  • 9