Add a click event to some text in ios NSString

无人久伴 提交于 2019-12-04 09:40:30

What if you used the value field to pass in the destination?

[attributedString addAttribute:NSLinkAttributeName
                         value:[@"destinationController1" stringByAppendingString:username]
                         range:range];

Then override the delegate method:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
    if ([URL.scheme isEqualToString:@"destinationController1"]) {
        // Launch View controller
        return NO;
    }
    return YES;
}

My solution requires the use of a UITextView (which is significantly easier, and I urge that you use it instead).

Swift

class ViewController: UIViewController {
    @IBOutlet weak var textView:UITextView!;

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let gestureRecognizer = UITapGestureRecognizer(target: self, action: "textViewTapped:");
        gestureRecognizer.numberOfTapsRequired = 1;
        gestureRecognizer.numberOfTouchesRequired = 1;
        self.textView.addGestureRecognizer(gestureRecognizer);
    }

    func textViewTapped(sender: UITapGestureRecognizer) {
        let wordTarget = "here";

        let word = UITextView.getWordAtPosition(sender.locationInView(self.textView), textView: self.textView);
        if word == wordTarget {
            let plainString = self.textView.attributedText.string;
            let substrings = NSMutableArray();
            let scanner = NSScanner(string: plainString);
            scanner.scanUpToString("#", intoString: nil);
            while !scanner.atEnd {
                var substring:NSString? = nil;
                scanner.scanString("#", intoString: nil);
                let space = " ";
                if scanner.scanUpToString(space, intoString: &substring) {
                    // If the space immediately followed the #, this will be skipped
                    substrings.addObject(substring!);
                }
                scanner.scanUpToString("#", intoString: nil);
                //Scan all characters before next #
            }
            println(substrings.description);
            //Now you got your substrings in an array, so use those for your data passing (in a segue maybe?)
            ...

        }
    }

}

extension UITextView {
    class func getWordAtPosition(position: CGPoint!, textView: UITextView!) -> String? {
        //Remove scrolloffset
        let correctedPoint = CGPointMake(position.x, textView.contentOffset.y + position.y);
        //Get location in text from uitextposition at a certian point
        let tapPosition = textView.closestPositionToPoint(correctedPoint);
        //Get word at the position, will return nil if its empty.
        let wordRange = textView.tokenizer.rangeEnclosingPosition(tapPosition, withGranularity: UITextGranularity.Word, inDirection: UITextLayoutDirection.Right.rawValue);
        return textView.textInRange(wordRange!);
    }
}

Objective-C

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(textViewTapped:)];
    gestureRecognizer.numberOfTouchesRequired = 1;
    gestureRecognizer.numberOfTapsRequired = 1;
    [self.textView addGestureRecognizer:gestureRecognizer];
}

- (void)textViewTapped:(UITapGestureRecognizer *)sender {
    NSString *wordTarget = @"here";

    NSString* word = [self getWordAtPosition:[sender locationInView:self.textView] textView:self.textView];
    if ([word isEqualToString:wordTarget]) {
        NSString *plainString = self.textView.attributedText.string;
        NSMutableArray* substrings = [[NSMutableArray alloc]init];
        NSScanner *scanner = [[NSScanner alloc]initWithString:plainString];
        [scanner scanUpToString:@"#" intoString:nil];
        while (![scanner isAtEnd]) {
            NSString* substring = nil;
            [scanner scanString:@"#" intoString:nil];
            NSString* space = @" ";
            if ([scanner scanUpToString:space intoString:&substring]) {
                [substrings addObject:substring];
            }
            [scanner scanUpToString:@"#" intoString:nil];
        }

        //Now you got your substrings in an array, so use those for your data passing (in a segue maybe?)
        ...

    }
}

- (NSString*)getWordAtPosition:(CGPoint)position textView:(UITextView *)textView {
    //remove scrollOffset
    CGPoint correctedPoint = CGPointMake(position.x, textView.contentOffset.y + position.y);
    UITextPosition *tapPosition = [textView closestPositionToPoint:correctedPoint];
    UITextRange *wordRange = [textView.tokenizer rangeEnclosingPosition:tapPosition withGranularity:UITextGranularityWord inDirection:UITextLayoutDirectionRight];
    return [textView textInRange:wordRange];
}

Basically you need to add a gesture recognizer to get the tap point in your textview. Then, you get the word using the category method provided in the extension area. After, you check what the word is (where we want the word "here"). Then, we collect the hashtags you have provided.

All you have to do is add a performSegueWithIdentifier method, and pass it accordingly.

In addition to @Nate Lee answer, updated the extension for Swift 4.0 version:

extension UITextView {
    class func getWordAtPosition(position: CGPoint!, textView: UITextView!) -> String? {
    //Remove scrolloffset
    let correctedPoint = CGPoint(x: position.x, y: (textView.contentOffset.y + position.y))
    //Get location in text from uitextposition at a certian point
    let tapPosition = textView.closestPosition(to: correctedPoint)
    //Get word at the position, will return nil if its empty.
    let wordRange = textView.tokenizer.rangeEnclosingPosition(tapPosition!, with: .word, inDirection: UITextLayoutDirection.right.rawValue)
    return textView.text(in: wordRange!)
    }
}

Swift 3:

Don't check on the URL.scheme attribute. Returned nil for me.

Do this:

attributedString.addAttribute(NSLinkAttributeName, value: "openToViewController", range: range)

Then use the absoluteString attribute on the URL to check on that value to your view of choice:

  func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool{
if (URL.absoluteString == "openToViewController") {
  let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as! UIViewController
  self.present(viewController, animated: true, completion: nil)
  return false
}
return true
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!