1

I am using this Extension to detect Hashtags inside a UILabel:

import UIKit

extension UILabel {

func resolveHashTags(){

    // turn string in to NSString
    let nsText:NSString = self.text!

    // this needs to be an array of NSString.  String does not work.
    let words:[NSString] = nsText.componentsSeparatedByString(" ")

    // you can't set the font size in the storyboard anymore, since it gets overridden here.
    let attrs = [
        NSFontAttributeName : UIFont.systemFontOfSize(17.0)
    ]

    // you can staple URLs onto attributed strings
    let attrString = NSMutableAttributedString(string: nsText as String, attributes:attrs)

    // tag each word if it has a hashtag
    for word in words {

        // found a word that is prepended by a hashtag!
        // homework for you: implement @mentions here too.
        if word.hasPrefix("#") {

            // a range is the character position, followed by how many characters are in the word.
            // we need this because we staple the "href" to this range.
            let matchRange:NSRange = nsText.rangeOfString(word as String)

            // convert the word from NSString to String
            // this allows us to call "dropFirst" to remove the hashtag
            var stringifiedWord:String = word as String

            // drop the hashtag
            stringifiedWord = String(stringifiedWord.characters.dropFirst())

            // check to see if the hashtag has numbers.
            // ribl is "#1" shouldn't be considered a hashtag.
            let digits = NSCharacterSet.decimalDigitCharacterSet()

            if let numbersExist = stringifiedWord.rangeOfCharacterFromSet(digits) {
                // hashtag contains a number, like "#1"
                // so don't make it clickable
            } else {
                // set a link for when the user clicks on this word.
                // it's not enough to use the word "hash", but you need the url scheme syntax "hash://"
                // note:  since it's a URL now, the color is set to the project's tint color
                attrString.addAttribute(NSLinkAttributeName, value: "hash:\(stringifiedWord)", range: matchRange)
            }

        }
    }
    self.attributedText = attrString
}

}

To use this, i do this:

self.myLabel.resolveHashTags()

But, how can i detect when a hashtag is tapped, and they do a print("hashtag clicked")?

Does anyone has any idea or suggestions on how i can do this?

Roduck Nickes
  • 1,021
  • 2
  • 15
  • 41

2 Answers2

1

You can implement the UITextViewDelegate method textView(_:shouldInteractWithURL URL:inRange:) which allows you to handle the link being clicked:

func textView(_ textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
    // ...check that this is a hashtag link, and not a regular link...
    print("hashtag clicked")
}
jtbandes
  • 115,675
  • 35
  • 233
  • 266
  • There is much discussion on this topic; see http://stackoverflow.com/questions/1256887/create-tap-able-links-in-the-nsattributedtext-of-a-uilabel – jtbandes Dec 20 '15 at 21:37
  • I actually made the extension code work with `UILabel`, but how can i detect the hashtag press on `UILabel`? – Roduck Nickes Dec 20 '15 at 21:38
  • That seems to be a different question; I can't answer it with the information you've given. – jtbandes Dec 20 '15 at 21:39
  • If i have a UILabel with hashtags(using the same extension as in my question), how can i detect when a hashtag is tapped? – Roduck Nickes Dec 20 '15 at 21:40
  • I think you will find everything you need at http://stackoverflow.com/questions/1256887/create-tap-able-links-in-the-nsattributedtext-of-a-uilabel – jtbandes Dec 20 '15 at 21:40
0
let label: UILabel = ... //This could possibly be an IBOutlet, or however you want to attempt to get a reference to the label

label.userInteractionEnabled = true //You have to enable user interaction on labels

let tapGesture = UITapGestureRecognizer(target: self, action: "labelTap:") //Create a tap gesture

label.addGestureRecognizer(tapGesture) //Set the labels gesture

At this point, you will need a labelTap function in your class. We will also need to make sure the function has a variable with it (notice how the action on the tapGesture includes a colon, thus suggesting that a variable is in the function).

It would look something like this:

func labelTap(gestureRecognizer: UIGestureRecognizer) {
  //This function will be called everytime your label is called
}

At this point you just add the needed logic into the labelTap function.

Edit: In response to your comment, here is some relevant code on how to check if there is, indeed, a hashtag in the label (This code is just adapted from your original resolveHashTags() function):

func labelTap(gestureRecognizer: UIGestureRecognizer) {

    // turn string in to NSString
    let nsText:NSString = label.text!

    // this needs to be an array of NSString.  String does not work.
    let words:[NSString] = nsText.componentsSeparatedByString(" ")

    // tag each word if it has a hashtag
    for word in words {

        // found a word that is prepended by a hashtag!
        // homework for you: implement @mentions here too.
        if word.hasPrefix("#") {

            // a range is the character position, followed by how many characters are in the word.
            // we need this because we staple the "href" to this range.
            let matchRange:NSRange = nsText.rangeOfString(word as String)

            // convert the word from NSString to String
            // this allows us to call "dropFirst" to remove the hashtag
            var stringifiedWord:String = word as String

            // drop the hashtag
            stringifiedWord = String(stringifiedWord.characters.dropFirst())

            // check to see if the hashtag has numbers.
            // ribl is "#1" shouldn't be considered a hashtag.
            let digits = NSCharacterSet.decimalDigitCharacterSet()

            if let numbersExist = stringifiedWord.rangeOfCharacterFromSet(digits) {
                // hashtag contains a number, like "#1"
                // so don't make it clickable
            } else {
                // a hashtag was clicked!
                print("A hashtag was clicked. The hashtag was: \(stringifiedWord)")
            }

        }
    }
}
Aaron
  • 757
  • 5
  • 18
  • Thanks! But it detect label click, not hashtag click. How can i do this? I tried this so far: http://pastebin.com/SffWwVmE – Roduck Nickes Dec 22 '15 at 01:32
  • Since the labelTap function will only be called when the label you assigned it to is clicked, you can simply reference the same label in it. So at this point, all you have to do is check the label's text for hashtags. I'll update my answer with relavent code. – Aaron Dec 22 '15 at 01:44
  • I tried like this: http://pastebin.com/eHp0D9tZ - But it print all hashtags in the uilabel when pressing the label. `self.arrayOfDetails[indexPath.item].text ` is the current label text btw. – Roduck Nickes Dec 22 '15 at 01:57
  • I've misunderstood your question. What you are trying to do is actually somewhat complex, as you would actually need to get the coordinates of the clicked area and determine what word it is. There are some nice third party libraries to do this, or, what @jtbandes said was correct, everything you need should be at this link (One of the answers is independent of third parties): http://stackoverflow.com/questions/1256887/create-tap-able-links-in-the-nsattributedtext-of-a-uilabel – Aaron Dec 22 '15 at 06:07