Get currently typed word in a UITextView
The UITextView delegate method : -textView:textView shouldChangeTextInRange:range replacementText:text
what actaully does is that it asks whether the specified text should be replaced in the text view in the specified range of textView.text
.
This method will be invoked each time when we type a charactor before updating that to the text view. That is why you are getting the range.location
as 0, when you type the very first character in the textView
.
Only if the return of this method is true, the textView
is getting updated with what we have typed in the textView
.
This is the definition of the parameters of the -textView:textView shouldChangeTextInRange:range replacementText:text
method as provided by apple:
range :- The current selection range. If the length of the range is 0, range reflects the current insertion point. If the user presses the Delete key, the length of the range is 1 and an empty string object replaces that single character.
text :- The text to insert.
So this is what the explanation for the method and your requirement can meet like as follows:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
//Un-commend this check below :If you want to detect the word only while new line or white space charactor input
//if ([text isEqualToString:@" "] || [text isEqualToString:@"\n"])
//{
// Getting the textView text upto the current editing location
NSString * stringToRange = [textView.text substringWithRange:NSMakeRange(0,range.location)];
// Appending the currently typed charactor
stringToRange = [stringToRange stringByAppendingString:text];
// Processing the last typed word
NSArray *wordArray = [stringToRange componentsSeparatedByString:@" "];
NSString * wordTyped = [wordArray lastObject];
// wordTyped will give you the last typed object
NSLog(@"\nWordTyped : %@",wordTyped);
//}
return YES;
}
Get the last word that is being typed
Try with below code, its working at my end.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let nsString = textView.text as NSString?
let newString = nsString?.replacingCharacters(in: range, with: text)
let arr = newString?.components(separatedBy: " ")
self.lblWord.text = arr?.last
return true
}
UITEXTVIEW: Get the recent word typed in uitextview
//This method looks for the recent string entered by user and then takes appropriate action.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
//Look for Space or any specific string such as a space
if ([text isEqualToString:@" "]) {
NSMutableCharacterSet *workingSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
NSRange newRange = [self.myTextView.text rangeOfCharacterFromSet:workingSet
options:NSBackwardsSearch
range:NSMakeRange(0, (currentLocation - 1))];
//The below code could be done in a better way...
UITextPosition *beginning = myTextView.beginningOfDocument;
UITextPosition *start = [myTextView positionFromPosition:beginning offset:currentLocation];
UITextPosition *end = [myTextView positionFromPosition:beginning offset:newRangeLocation+1];
UITextRange *textRange = [myTextView textRangeFromPosition:end toPosition:start];
NSString* str = [self.myTextView textInRange:textRange];
}
}
UITextField get currently edited word
Ok I found a way to do it quite easily. Maybe someone will find it useful:
UITextRange* selectedRange = [textField selectedTextRange];
NSInteger cursorOffset = [textField offsetFromPosition:0 toPosition:selectedRange.start];
NSString* text = textField.text;
NSString* substring = [text substringToIndex:cursorOffset];
NSString* editedWord = [[substring componentsSeparatedByString:@" "] lastObject];
How to detect a string after the '@' is typed in a textview
So you aren't currently getting the whole word in currentWord
. It looks like you're only getting the @
character. currentWord
is a variable and it doesn't look like you're properly iterating through all of the characters in the textField. This is how I would handle that:
if let splitText = textField.text?.split(separator: " ") {
for word in splitText {
if word.hasPrefix("@") {
print(word) // call whatever function you need here
} else {
print("NOPE")
}
}
} else {
print("No Text!!")
}
This will only fire when it finds an @
and the word
contains the @
and every character after the @
until a " "
(space)
Get current paragraph in UITextView?
It sounds like you need NSString
's paragraphRangeForRange:
method:
let composeText = composeTextView.text as NSString
let paragraphRange = composeText.paragraphRangeForRange(composeTextView.selectedRange)
print(composeText.substringWithRange(paragraphRange))
Get tapped word from UITextView in Swift
You need to add the UITapGestureRecognizer
to the UITextView
that you want to be able to tap. You are presently adding the UITapGestureRecognizer
to your ViewController
's view
. That is why the cast is getting you into trouble. You are trying to cast a UIView
to a UITextView
.
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textTapped))
tapGesture.numberOfTapsRequired = 1
myTextView.addGestureRecognizer(tapGesture)
Technically recognizer.view
is an optional type (UIView!
) and could be nil
, but it seems unlikely that your textTapped()
would be called it that wasn't set. Likewise, the layoutManager
is of type NSLayoutManager!
. To be on the safe side though, the Swift way to do this is:
guard let textView = recognizer.view as? UITextView, let layoutManager = textView.layoutManager else {
return
}
// code using textView and layoutManager goes here
In fact, if you had written it this way, you wouldn't have crashed because the conditional cast of the UIView
to UITextView
would not have succeeded.
To make this all work then, add attributes to your attributed string that you will extract in your textTapped routine:
var beginning = NSMutableAttributedString(string: "To the north you see a ")
var attrs = [NSFontAttributeName: UIFont.systemFontOfSize(19.0), "idnum": "1", "desc": "old building"]
var condemned = NSMutableAttributedString(string: "condemned building", attributes: attrs)
beginning.appendAttributedString(condemned)
attrs = [NSFontAttributeName: UIFont.systemFontOfSize(19.0), "idnum": "2", "desc": "lake"]
var lake = NSMutableAttributedString(string: " on a small lake", attributes: attrs)
beginning.appendAttributedString(lake)
myTextView.attributedText = beginning
Here's the full textTapped
:
@objc func textTapped(recognizer: UITapGestureRecognizer) {
guard let textView = recognizer.view as? UITextView, let layoutManager = textView.layoutManager else {
return
}
var location: CGPoint = recognizer.locationInView(textView)
location.x -= textView.textContainerInset.left
location.y -= textView.textContainerInset.top
/*
Here is what the Documentation looks like :
Returns the index of the character falling under the given point,
expressed in the given container's coordinate system.
If no character is under the point, the nearest character is returned,
where nearest is defined according to the requirements of selection by touch or mouse.
This is not simply equivalent to taking the result of the corresponding
glyph index method and converting it to a character index, because in some
cases a single glyph represents more than one selectable character, for example an fi ligature glyph.
In that case, there will be an insertion point within the glyph,
and this method will return one character or the other, depending on whether the specified
point lies to the left or the right of that insertion point.
In general, this method will return only character indexes for which there
is an insertion point (see next method). The partial fraction is a fraction of the distance
from the insertion point logically before the given character to the next one,
which may be either to the right or to the left depending on directionality.
*/
var charIndex = layoutManager.characterIndexForPoint(location, inTextContainer: textView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
guard charIndex < textView.textStorage.length else {
return
}
var range = NSRange(location: 0, length: 0)
if let idval = textView.attributedText?.attribute("idnum", atIndex: charIndex, effectiveRange: &range) as? NSString {
print("id value: \(idval)")
print("charIndex: \(charIndex)")
print("range.location = \(range.location)")
print("range.length = \(range.length)")
let tappedPhrase = (textView.attributedText.string as NSString).substringWithRange(range)
print("tapped phrase: \(tappedPhrase)")
var mutableText = textView.attributedText.mutableCopy() as NSMutableAttributedString
mutableText.addAttributes([NSForegroundColorAttributeName: UIColor.redColor()], range: range)
textView.attributedText = mutableText
}
if let desc = textView.attributedText?.attribute("desc", atIndex: charIndex, effectiveRange: &range) as? NSString {
print("desc: \(desc)")
}
}
How can I get the current selected line number inside UITextView?
EDIT: I've obviously ignored the currently selected part of your question.
I'll still keep the code here in case someone needs it.
Have you tried counting the newline separator?
let str = "First\nSecond\nThird"
let tok = str.componentsSeparatedByString("\n")
print(tok.count) // Hopefully prints "3"
Get word from character index in textView (iOS)
The issue apparently seemed to stem from the .x and .y values I set after getting location. All I had to do was remove these lines:
location.x -= textView.textContainerInset.left
location.y -= textView.textContainerInset.top
Related Topics
Does "Let _ = ..." (Let Underscore Equal) Have Any Use in Swift
iOS Wkwebview Swift JavaScript Enable
Shared Iad Banner Bannerviewdidloadad Not Being Called
Calculate The Range of Visible Text in UIlabel
iOS 13.2 Message: Nehelper Sent Invalid Result Code [1] for Wi-Fi Information Request
Uitableview Scroll Erases Data in Text Field Inside UItableviewcell
Sprite Frame Animation Cocos2D 3.0
Ckfetchnotificationchangesoperation Sometimes Does Not Return Update, Delete Notifications
Uitableview Has Unwanted Animation When Reloaddata Is Called
How to Include Openssl on an iOS Project in a Way That Works
Exceeding Max Text("") Concatenation Length - Swiftui -
Objc Protocol Implementation in Swift
Swift Unrecognized Selector Sent to Instance - What Am I Missing
Getting Email Address from Linkedin API
Is There a Way of Automatically Writing Custom Values to The Bundle's .Plist During a Build Phase