Answer the question
In order to leave comments, you need to log in
How to correctly recognize mentions (mentions) with underscore through UITapGestureRecognizer in UITextView?
I have a method that recognizes nicknames or hashtags by tap.
The problem is that it does not work correctly if there is an underscore in the nickname. Ignores it, i.e. recognizes it as a space.
func tapRecognized(tapGesture: UITapGestureRecognizer) {
var wordString: String? // The String value of the word to pass into callback function
var char: NSAttributedString! //The character the user clicks on. It is non optional because if the user clicks on nothing, char will be a space or " "
var word: NSMutableAttributedString? //The word the user clicks on
var isHashtag: AnyObject?
var isAtMention: AnyObject?
// Gets the range of the character at the place the user taps
let point = tapGesture.location(in: self)
let charPosition = closestPosition(to: point)
let charRange = tokenizer.rangeEnclosingPosition(charPosition!, with: .character, inDirection: 1)
//Checks if the user has tapped on a character.
if charRange != nil {
let location = offset(from: beginningOfDocument, to: charRange!.start)
let length = offset(from: charRange!.start, to: charRange!.end)
let attrRange = NSMakeRange(location, length)
char = attributedText.attributedSubstring(from: attrRange)
//If the user has not clicked on anything, exit the function
if char.string == " "{
print("User clicked on nothing")
return
}
// Checks the character's attribute, if any
isHashtag = char?.attribute("Hashtag", at: 0, longestEffectiveRange: nil, in: NSMakeRange(0, char!.length)) as AnyObject?
isAtMention = char?.attribute("Mention", at: 0, longestEffectiveRange: nil, in: NSMakeRange(0, char!.length)) as AnyObject?
}
// Gets the range of the word at the place user taps
let wordRange = tokenizer.rangeEnclosingPosition(charPosition!, with: .word, inDirection: 1)
/*
Check if wordRange is nil or not. The wordRange is nil if:
1. The User clicks on the "#" or "@"
2. The User has not clicked on anything. We already checked whether or not the user clicks on nothing so 1 is the only possibility
*/
if wordRange != nil{
// Get the word. This will not work if the char is "#" or "@" ie, if the user clicked on the # or @ in front of the word
let wordLocation = offset(from: beginningOfDocument, to: wordRange!.start)
let wordLength = offset(from: wordRange!.start, to: wordRange!.end)
let wordAttrRange = NSMakeRange(wordLocation, wordLength)
word = attributedText.attributedSubstring(from: wordAttrRange) as? NSMutableAttributedString
if let stringFromWord = word?.string {
wordString = stringFromWord
}
} else {
/*
Because the user has clicked on the @ or # in front of the word, word will be nil as
tokenizer.rangeEnclosingPosition(charPosition!, with: .word, inDirection: 1) does not work with special characters.
What I am doing here is modifying the x position of the point the user taps the screen. Moving it to the right by about 12 points will move the point where we want to detect for a word, ie to the right of the # or @ symbol and onto the word's text
*/
var modifiedPoint = point
modifiedPoint.x += 12
let modifiedPosition = closestPosition(to: modifiedPoint)
let modifedWordRange = tokenizer.rangeEnclosingPosition(modifiedPosition!, with: .word, inDirection: 1)
if modifedWordRange != nil{
let wordLocation = offset(from: beginningOfDocument, to: modifedWordRange!.start)
let wordLength = offset(from: modifedWordRange!.start, to: modifedWordRange!.end)
let wordAttrRange = NSMakeRange(wordLocation, wordLength)
word = attributedText.attributedSubstring(from: wordAttrRange) as? NSMutableAttributedString
wordString = word!.string
}
}
if let stringToPass = wordString {
// Runs callback function if word is a Hashtag or Mention
if isHashtag != nil && callBack != nil {
callBack!(stringToPass, wordType.hashtag)
} else if isAtMention != nil && callBack != nil {
callBack!(stringToPass, wordType.mention)
}
}
}
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question