I have a if/else statement in my objective-c code. The if/else statement runs like this:
-(void)textViewDidBeginEditing:(UITextView *)textView
{
if(textView==self.heardTextView)
{
NSString *string = textView.text;
if ([string rangeOfString:#"CLOSER"].location == NSNotFound)
{
NSLog(#"closest");
}
}
}
The premise of the if/else statement is - if the textview equals a certain word some code will run. But this code isn't running.
I have put a breakpoint on my code and a NSLOG and nothing.
check your text field delegate if you not set your delegate then it's not called..
In your Viewcontroller.H
select your textview give delegate on textview.
First you need to set the delegate of the text view. You can do this with Interface Builder, but if you prefer using code you can do this in the viewDidLoad method of your view controller:
myTextView.delegate = self;
Now, when do you want the NSLog statement to be executed? Right now it looks like it will be run only if you type "CLOSER", then make the text view lose focus and then click on it again.
If you want the NSLog to run as you type, you should use:
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
And also be careful, you need to calculate the next string value in the text field before testing its contents:
NSString *finalText = [textField.text stringByReplacingCharactersInRange:range withString:string];
Check your delegates, you must not have made the delegate of your textview as self. Check it once again. Or you might have done to some other class.
Related
I added a feedback box inside my IOS application, and I want it to take only text to submit the response from the user, but when I tried to enter a white spaces inside the box it took it as a text and accept the submitting! How can I prevent that?
Specify the UIViewController as the delegate to your text view (you can do this either programmatically or specify the delegate in Interface Builder); and
Your UITextViewDelegate method shouldChangeTextInRange needs to check to see if the string to be inserted contains a space:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([text rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].location != NSNotFound) {
return NO;
}
return YES;
}
When using a UITextView to gather user input in Objective-C, how can I limit the user from trying to do more than one line break at a time?
So, this would be fine:
This is my text.
Here is some more text.
But this would not be fine:
This is my text.
Here is some more text way down here.
In your ViewController.h add UITextViewDelegate:
YourViewController : UIViewController <UITextViewDelegate>
and in the ViewController.m implement the method textView:shouldChangeTextInRange:replacementText: this way:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([text isEqualToString:#"\n"]) {
NSMutableString *futureString = [textView.text mutableCopy];
[futureString insertString:text atIndex:range.location];
NSRange rangeOflineBreaks = [futureString rangeOfString:#"\n\n\n"];
if (rangeOflineBreaks.location != NSNotFound) {
return NO;
}
}
return YES;
}
This will be executed every time before the user wants to add some text to the textView and wont let him add another line break if it notices that he wants to add a line break and it finds, after trying adding it (that's why the futureString name) a triple line break mode. In that case he wont let the user add another line break.
Try it out, it should work :)
PS: Don't forget to set your textView delegate the viewController in the viewDidLoad (yourTextView.delegate = self)
I have a table view. In cellForRowAtIndexPath I have a cell and in that cell there is UITextField. I set textfield's delegate like this: cell.textField.delegate = self;. I need to call my API on third character. So when user types 3 character in textfield, API is called hence shouldChangeCharactersInRange.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField.text.length >= 2) {
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring
stringByReplacingCharactersInRange:range withString:string];
[API CALLED WITH BLOCK WITH TEXTFIELD TEXT AS PARAMETER:substring];
}
return YES;
}
The problem is that when I type for example "abc" shouldChangeCharactersInRange is called first time and parameter is "abc". Second after, shouldChangeCharactersInRange is again called and my textfield has another added character which I did not type and it is always last character that is copied. So in this example, it sends "abcc". Do you know, what is the problem?
Setting breakpoints in that delegate method can sometimes cause the method to be fired twice. Try removing any breakpoints that are hit here or in your API method and test again.
This can be replicated easily. Create a new project, add a UITextField outlet and set the delegate to your controller. Implement textField:shouldChangeCharactersInRange: in your controller and set a breakpoint on an NSLog statement or something, and return YES. Sometimes, after telling the debugger to continue, a second keystroke will be generated and will hit your delegate method again.
I would recommend using a textFieldDidChange instead as this occurs after the text has been typed so you don't have to deal with appending strings. From there you can just check 'text.lenght >=3' to fire your API call.
You can add the event like this:
[textField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
EDIT:
This code works for me. I sent up the delegate in the cell class.
#import "AnotherTableViewCell.h"
#implementation AnotherTableViewCell
#synthesize myTextField = _myTextField;
- (void)awakeFromNib {
// Initialization code
_myTextField.delegate=self;
[_myTextField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)textFieldDidChange:(UITextField*)textField{
if (textField.text.length>=3) {
NSLog(#"Text >= 3: %#",textField.text);
}
}
#end
I am trying to achieve the same effect as Facebook's new status field: place something next to the last character which cannot be modified or selected by the user (for example, a tag: "with Joh Doe").
What's the best way of achieving it?
Thanks
Nick
An easier solution would be to simply make the last n characters in the TextView not editable. Then let the TextView handle moving and wrapping the text as needed. I would guess that is what Facebook is doing, just with some attributed text at the end.
In your ViewControllers.h, make sure the viewController conforms to the UITextViewDelegate as follows.
#interface ViewController : UIViewController <UITextViewDelegate>
Then in the viewDidLoad: method, set the delegate for the UITextView to the ViewController. You can also add your fixed text.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myTextView.delegate = self;
self.myTextView.text = " posted by Mike";
}
Then, we will use the shouldChangeCharactersInRange: method to prevent the user from editing the text at the end you want to preserve.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
BOOL deleteKeyPressed = ([text length] == 0 && range.length > 0);
if( range.location > (textView.text.length - #" - posted by Mike".length) || (deleteKeyPressed && range.location > (textView.text.length - #" - posted by Mike".length)) )
{
return NO;
}
return YES;
}
I think this should get you started and make you life easier than finding the end of the last text, then putting another view at the end that may need to wrap if there is not enough room to fit it.
So to prevent the user from selecting the "reserved" text, add the following delegate method to your ViewController's .m:
-(void) textViewDidChangeSelection:(UITextView *)textView
{
if( textView.selectedRange.location > (textView.text.length - #" - posted by Mike".length) )
{
[textView setSelectedRange:NSMakeRange((textView.text.length - #" - posted by Mike".length), 0 )];
}
}
You'll still need to handle if the user selects all the text, and chooses to "cut" or "paste", but that should just be another special case in shouldChangeTextInRange. I'll let you figure that one out - shouldn't be hard. Certainly a lot easier than trying to dynamically place, size, and wrap a TextView within another TextView.
I have a UITextView. I have the delegate for myTextView set to self and, when I do normal editing, this method calls just fine:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSLog(#"Called");
}
In my app, I call in my code: [myTextView insertText:#"Hello World"];. When I do, I need to call textView:shouldChangeTextInRange:replacementText: after the text is inserted. How do I do this?
Call it explicitly. Call it before editing and only perform the edit if it returns YES. To call it explicitly you need to know the selected range (get the selected range with selectedTextRange), that's it. You already have the text to add and the text view.
Thanks for the answer, #Wain!
Here's what worked:
- (void)insertText
{
NSString *stringToAdd = #"Hello World";
NSString *replacementText = [myTextView.text stringByAppendingString:stringToAdd];
[napkinTextView insertText:stringToAdd];
[self textView:myTextView shouldChangeTextInRange:NSMakeRange(0, stringToAdd.length) replacementText:replacementText];
}