How to prevent user to editing from given range in iPhone textView - iphone

I am currently worked on simple textview application in which I need prevent user to write data in textView & after preventing he may be change other value of textview. Below is my code for prevernting user to write into textview.
- (void)textViewDidChange:(UITextView *)textView
{
NSString *textValue=textView.text;
NSInteger intLen=[textValue length];
if(intlen>280){
textView.editable=No;
}
else
{
textView.editable=YES;
if(intLen <=140)
{
intLen=140-intLen;
intSMSValue=1;
lblSmscounter.text=[[NSNumber numberWithInt:intSMSValue]stringValue];
lblCountChar.text=[[NSNumber numberWithInt:intLen] stringValue];
}
if((intLen>140)&&(intLen <=280))
{
intLen=280-intLen;
intSMSValue=2;
lblSmscounter.text=[[NSNumber numberWithInt:intSMSValue]stringValue];
lblCountChar.text=[[NSNumber numberWithInt:intLen] stringValue];
}
}
}
But in my code I am prevent user to write more than 280 bt user caneditable the previous text.

Try delegate method
(BOOL)textView:(UITextView )textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString)text{
}
If the range of editable text is ok, return yes.

Related

Make second UITextField firstresponder after the first UITextField did finish editing and press Done

I have created two UITextFields dynamically, when tapped on a certain CA Layer. I have made the first textfield the first responder, what I want is, when I enter text in first Textfield and press done, I want the second textfield to be the first responder.
n thats what I did for this in textFieldShouldReturn.
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (titleField.returnKeyType== UIReturnKeyDone) {
NSString *title = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (title.length>0 )
{
[self changeLayersTitle:title];
}
[dateField becomeFirstResponder];
if (dateField.returnKeyType==UIReturnKeyDone)
{
NSString *date = [dateField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (date.length>0)
{
[self changeLayersDate:date];
}
}
[dateField resignFirstResponder];
[bgLayer removeFromSuperlayer];
[titleField removeFromSuperview];
[dateField removeFromSuperview];
}
return NO;
}
Now, when I enter press Done after entring text in first one, it dismissed both of the textfields, bt shows me the keyboard.
So, what am I missing or did wrong or do I have to put it somewhere else. please help me out.
I'm not sure why you were comparing the returnKeyType property of the text fields. You should compare the text fields for equality, and if the return key was pressed on the first text field, then make the second text field the new responder.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == titleField) {
[dateField becomeFirstResponder];
}
else if (textField == dateField) {
// Return button pressed on 2nd field. Do something
}
return YES;
}
In your done button callback method, can't you just set your second text field as the first responder?
You don't need to resignFirstResponder on your first text field.

Confirm UITextview auto-complete

This seems impossible, but maybe someone else has had the same problem.
Is it possible for me to accept an autocomplete programmatically, or in some way get the suggested word that pops up? My problem is that I'm capturing the return/backspace keystroke and then move focus to another textview. When enter/backspace is hit, the textview will ignore the auto-suggested word. It seems that it is only possible to accept an autocompletion by hit space/dot (and return for new row). With this code:
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text {
NSRange textViewRange = [textView selectedRange];
// Handle newrow and backspace.
if(([text length] == 0) && (textViewRange.location== 0) && textViewRange.length==0){
// BACKSPACE KEYSTROKE
[delegate doSomethingWhenBackspace];
return NO;
}else if ([text isEqualToString:#"\n"]){
// RETURN KEYSTROKE
[delegate doSomethingWhenReturn];
return NO;
}
return YES;
}
I tried to programmatically add "space" when the return key is hit but that also ignores the auto-completed word.
else if ([text isEqualToString:#"\n"]){
// Tryin to accept autocomplete with no result.
textview.text = [textview.text stringByAppendingString:#" "];
// RETURN KEYSTROKE
[delegate doSomethingWhenReturn];
return NO;
}
Any suggestions?
Call -resignFirstResponder (i.e. [textView resignFirstResponder]) on the text view or text field which needs to accept autocomplete results: UIKit will change the .text property to include the autocorrected text.
If you want to keep the keyboard up after your first view resigns first responder, pass the firstResponder responsibility onto your next text input view with [anotherTextView becomeFirstResponder].
For backspace and space u can use this condition
if ([[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]==0)
{
[delegate doSomethingWhenBackspace];
return NO;
}
I've had a very similar problem, I was making an app that had to read every letter in a text view and I has issues when Autocomplete inserted words because it was saving it as if it was one letter.
you could add each character to an array and then check to see if any are over 1 string in length. Or you could add each character that is put in into an array and then run something like
NSString *string = text;
NSMutableArray *array = [NSMutableArray new];
for (int i=0; i<string.length; i++) {
[array addObject:[string substringWithRange:NSMakeRange(i, 1)]];
}
to add each character individually, by comparing the two arrays you could determine if autocorrect has been used and with what word/s.
Hope this will help.

textFieldDidBeginEditing: for more than one textfield

I am fairly new to iphone programming and here I am facing some issues. Now in my application, I have two textfields and I want to fire an event while second textfield starts editing. now I am using following function
- (void)textFieldDidBeginEditing:(UITextField *)textField
but the thing is the event is being fired when the first textfield starts editing. It does not wait for the second text field. Is there any way I can use this function for the second textfield or may be somehow could know and pass it the value of the active textfield?
I tried writing the name of the textfield instead of (UITextField *)textField in the function but still the same result.
If I were you , I would set a tag (in Interface Builder) of the second textField to 2, or something similar. Then you can just do this:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
if (textField.tag == 2) {
//this is textfield 2, so call your method here
}
}
EDIT: Please do this to see if the method is even called:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
NSLog(#"The method was called");
}
For Swift 2.2
func textFieldDidBeginEditing(textField: UITextField) {
if textField.tag == 2 {
//this is textfield 2, so call your method here
}
}
That delegate method is gonna get called everytime the editing of ANY text field is started, so it should be you who controls what is done when this happens. I suggest you to do something like:
-(void)textFieldDidBeginEditing: (UITextField *)textField
{
if (textField == mySecondTextField)
{
//Do what you need
}
else
{
//Do nothing
}
}
I hope it helps you!
Utilitize the tag property in Interface Builder to identify your view objects in your application at runtime. It will make life a lot easier, especially when you get ready to localize your application for different languages.
In your header file for your view controller
#define kUsernameField 100
#define kPasswordField 101
#define kStartButton 300
In the view controller implementation file
- (void)textFieldDidBeginEditing:(UITextField *)textField {
switch (textField.tag) {
case kUsernameField:
// do user name stuff
break;
case kPasswordField:
// do password stuff
break;
default:
NSLog(#"No case statement for %#", [textField description]);
break;
}
}
You will find a lot of tutorial out there that use the title field of UIButton to identify them. For example:
- (IBAction)buttonTouchUp:(id)sender {
UIButton *button = (UIButton *)sender;
// don't like
if ([button.currentTitle isEqualToString:#"Start"] == NSOrderedSame) {
// because if localize your for other language then you will have
// include code for those other language
// French: Démarrer
// Spanish: Inicio
// blah blah blah
}
// better
if (button.tag == kStartButton) {
// very simple, no code changes for localization
// blah blah blah
}
}
If you are creating the object with code, you can set the tag:
button.tag = kStartButton;
// or
[button setTag:kStartButton];
You must declare first UITextFieldDelegate in your controller .h
And set the delegate of your text field. ex. myInput.delegate = self;
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if ([sender isEqual:myInput])
{
NSLog(#"test");
}
}
This works perfectly for me.
Have you checked if your second textViews delegate is set to self ? I had the same issue where I had forgotten to set the delegate of other textFields and hence the delegate method was not firing.
Please have a look to my answer in this Question, it's exactly what you're looking for
Objective C: what is a "(id) sender"?

Interface Builder Tab Order Typing

I have noticed, in one of my views in an iPad app I am building the next button on the keyboard goes through all the UITextFields from left to right down the screen.
Is it possible somehow to make it go top to bottom then right, top to bottom?
So say I have to two long columns of text fields, I wan to go top to bottom not left to right, make sense?
Any help appreciated, thanks.
I don't think there is a way through IB, but you can do this way in code. You're not actually tabbing, you'd be using the return key.
Put this in your UITextField's delegate:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
BOOL shouldChangeText = YES;
if ([text isEqualToString:#"\n"]) {
// Find the next entry field
BOOL isLastField = YES;
for (UIView *view in [self entryFields]) {
if (view.tag == (textView.tag + 1)) {
[view becomeFirstResponder];
isLastField = NO;
break;
}
}
if (isLastField) {
[textView resignFirstResponder];
}
shouldChangeText = NO;
}
return shouldChangeText;
}
Found here: http://iphoneincubator.com/blog/tag/uitextfield
You'll want to implement UITextFieldDelegate's - (BOOL)textFieldShouldReturn:(UITextField *)textField method. An example of how to use this method to control the order is in this question.
I would like to elaborate on #sprocket's answer addressing the same issue. Just because something works out of the box doesn't mean you should stop thinking about a better way -- or even the right way -- of doing something. As he noticed the behavior is undocumented but fits our needs most of the time.
This wasn't enough for me though. Think of a RTL language and tabs would still tab left-to-right, not to mention the behavior is entirely different from simulator to device (device doesn't focus the first input upon tab). Most importantly though, Apple's undocumented implementation seems to only consider views currently installed in the view hierarchy.
Think of a form in form of (no pun intended) a table view. Each cell holds a single control, hence not all form elements may be visible at the same time. Apple would just cycle back up once you reached the bottommost (on screen!) control, instead of scrolling further down. This behavior is most definitely not what we desire.
So here's what I've come up with. Your form should be managed by a view controller, and view controllers are part of the responder chain. So you're perfectly free to implement the following methods:
#pragma mark - Key Commands
- (NSArray *)keyCommands
{
static NSArray *commands;
static dispatch_once_t once;
dispatch_once(&once, ^{
UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:#"\t" modifierFlags:0 action:#selector(tabForward:)];
UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:#"\t" modifierFlags:UIKeyModifierShift action:#selector(tabBackward:)];
commands = #[forward, backward];
});
return commands;
}
- (void)tabForward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.firstObject becomeFirstResponder];
}
- (void)tabBackward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls.reverseObjectEnumerator) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.lastObject becomeFirstResponder];
}
Additional logic for scrolling offscreen responders visible beforehand may apply.
Another advantage of this approach is that you don't need to subclass all kinds of controls you may want to display (like UITextFields) but can instead manage the logic at controller level, where, let's be honest, is the right place to do so.

UIKeyboard turn Caps Lock on

I need my user to input some data like DF-DJSL so I put this in the code:
theTextField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
But unfortunately what happens is the first to letter type in CAPS but then letter immediately after typing the hyphen will be in lower case and then the rest return to CAPS therefore producing output like this (unless the user manually taps the shift button after typing a hyphen): DF-dJSL
How can I fix this?
Many Thanks
You don't mention which SDK you're using, but against 3.0 and above I see your desired behaviour.
That said, you could always change the text to upper case when they finish editing using the textFieldDidEndEditing method from the delegate:
- (void)textFieldDidEndEditing:(UITextField *)textField {
NSString *textToUpper = [textField.text uppercaseString];
[theTextField setText:textToUpper];
}
Or, by setting up a notification on the textfield when it changes, you could change the text as it is being typed:
// setup the UITextField
{
theTextField.delegate = self;
theTextField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
[theTextField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
}
You have to do it this way since, unlike UISearchBar, UITextField doesn't implement textDidChange. Something like this, perhaps?
- (void)textFieldDidChange:(UITextField *)textField {
NSRange range = [textField.text rangeOfString : #"-"];
if (range.location != NSNotFound) {
theTextField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
}
}