Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect Link or URL in ASTextNode AsyncDisplayKit

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

like image 781
Mukesh Avatar asked Jan 07 '23 07:01

Mukesh


2 Answers

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 }
 }
like image 164
Bas Avatar answered Jan 14 '23 15:01

Bas


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.

like image 37
konradholub Avatar answered Jan 14 '23 17:01

konradholub