Limiting pasted string length in UITextView or UITextField - iphone

The problem of limiting strings that are directly entered into a UITextView or UITextField has been addressed on SO before:
iPhone SDK: Set Max Character length TextField
iPhone sdk 3.0 issue
However now with OS 3.0 copy-and-paste becomes an issue, as the solutions in the above SO questions don’t prevent pasting additional characters (i.e. you cannot type more than 10 characters into a field that is configured with the above solutions but you can easily paste 100 characters into the same field).
Is there a means of preventing directly entered string and pasted string overflow?

I was able to restrict entered and pasted text by conforming to the textViewDidChange: method within the UITextViewDelegate protocol.
- (void)textViewDidChange:(UITextView *)textView
{
if (textView.text.length >= 10)
{
textView.text = [textView.text substringToIndex:10];
}
}
But I still consider this kind of an ugly hack, and it seems Apple should have provided some kind of "maxLength" property of UITextFields and UITextViews.
If anyone is aware of a better solution, please do tell.

In my experience just implementing the delegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
works with pasting. The entire pasted string comes across in the replacementString: argument. Just check it's length, and if it's longer than your max length, then just return NO from this delegate method. This causes nothing to be pasted. Alternatively you could substring it like the earlier answer suggested, but this works to prevent the paste at all if it's too long, if that's what you want.

Changing the text after it's inserted in textViewDidChange: causes the app to crash if the user presses 'Undo' after the paste.
I played around for quite a bit and was able to get a working solution. Basically the logic is, do not allow the paste if the total length is greater than the max characters, detect the amount that is overflown and insert only the partial string.
Using this solution your pasteboard and undo manager will work as expected.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
NSInteger newLength = textView.text.length - range.length + text.length;
if (newLength > MAX_LENGTH) {
NSInteger overflow = newLength - MAX_LENGTH;
dispatch_async(dispatch_get_main_queue(), ^{
UITextPosition *start = [textView positionFromPosition:nil offset:range.location];
UITextPosition *end = [textView positionFromPosition:nil offset:NSMaxRange(range)];
UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
[textView replaceRange:textRange withText:[text substringToIndex:text.length - overflow]];
});
return NO;
}
return YES;
}

This code won't let user to input more characters than maxCharacters.
Paste command will do nothing, if pasted text will exceed this limit.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
return newText.count <= maxCharacters;
}

One of the answers in the first question you linked above to should work, namely using something like
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(limitTextField:) name:#"UITextFieldTextDidChangeNotification" object:myTextField];
to watch for changes to the text in the UITextField and shorten it when appropriate.

Also, string length as in '[string length]' is one thing, but one often needs to truncate to a byte count in a certain encoding. I needed to truncate typing and pasting into a UITextView to a max UTF8 count, here's how I did it. (Doing something similar for UITextField is an exercise to the reader.)
NSString+TruncateUTF8.h
#import <Foundation/Foundation.h>
#interface NSString (TruncateUTF8)
- (NSString *)stringTruncatedToMaxUTF8ByteCount:(NSUInteger)maxCount;
#end
NSString+TruncateUTF8.m
#import "NSString+TruncateUTF8.h"
#implementation NSString (TruncateUTF8)
- (NSString *)stringTruncatedToMaxUTF8ByteCount:(NSUInteger)maxCount {
NSRange truncatedRange = (NSRange){0, MIN(maxCount, self.length)};
NSInteger byteCount;
// subtract from this range to account for the difference between NSString's
// length and the string byte count in utf8 encoding
do {
NSString *truncatedText = [self substringWithRange:truncatedRange];
byteCount = [truncatedText lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
if (byteCount > maxCount) {
// what do we subtract from the length to account for this excess count?
// not the count itself, because the length isn't in bytes but utf16 units
// one of which might correspond to 4 utf8 bytes (i think)
NSUInteger excess = byteCount - maxCount;
truncatedRange.length -= ceil(excess / 4.0);
continue;
}
} while (byteCount > maxCount);
// subtract more from this range so it ends at a grapheme cluster boundary
for (; truncatedRange.length > 0; truncatedRange.length -= 1) {
NSRange revisedRange = [self rangeOfComposedCharacterSequencesForRange:truncatedRange];
if (revisedRange.length == truncatedRange.length)
break;
}
return (truncatedRange.length < self.length) ? [self substringWithRange:truncatedRange] : self;
}
#end
// tested using:
// NSString *utf8TestString = #"Hello world, Καλημέρα κόσμε, コンニチハ ∀x∈ℝ ıntəˈnæʃənəl ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ STARGΛ̊TE γνωρίζω გთხოვთ Зарегистрируйтесь ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช ሰማይ አይታረስ ንጉሥ አይከሰስ። ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ ░░▒▒▓▓██ ▁▂▃▄▅▆▇█";
// NSString *truncatedString;
// NSUInteger byteCount = [utf8TestString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
// NSLog(#"length %d: %p %#", (int)byteCount, utf8TestString, utf8TestString);
// for (; byteCount > 0; --byteCount) {
// truncatedString = [utf8TestString stringTruncatedToMaxUTF8ByteCount:byteCount];
// NSLog(#"truncate to length %d: %p %# (%d)", (int)byteCount, truncatedString, truncatedString, (int)[truncatedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
// }
MyViewController.m
#import "NSString+TruncateUTF8.h"
...
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)replacementText
{
NSMutableString *newText = textView.text.mutableCopy;
[newText replaceCharactersInRange:range withString:replacementText];
// if making string larger then potentially reject
NSUInteger replacementTextLength = replacementText.length;
if (self.maxByteCount > 0 && replacementTextLength > range.length) {
// reject if too long and adding just 1 character
if (replacementTextLength == 1 && [newText lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > self.maxByteCount) {
return NO;
}
// if adding multiple charaters, ie. pasting, don't reject altogether but instead return YES
// to accept and truncate immediately after, see http://stackoverflow.com/a/23155325/592739
if (replacementTextLength > 1) {
NSString *truncatedText = [newText stringTruncatedToMaxUTF8ByteCount:self.maxByteCount]; // returns same string if truncation needed
if (truncatedText != newText) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0LL), dispatch_get_main_queue(), ^{
UITextPosition *replaceStart = [textView positionFromPosition:textView.beginningOfDocument offset:range.location];
UITextRange *textRange = [textView textRangeFromPosition:replaceStart toPosition:textView.endOfDocument];
[textView replaceRange:textRange withText:[truncatedText substringFromIndex:range.location]];
self.rowDescriptor.value = (truncatedText.length > 0) ? truncatedText : nil;
});
}
}
}
[self updatedFieldWithString:(newText.length > 0) ? newText : nil]; // my method
return YES;
}

You can know the pasted string if you check for string.length in shouldChangeCharactersIn range: delegate method
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.length > 1 {
//pasted string
// do you stuff like trim
} else {
//typed string
}
return true
}

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if(string.length>10){
return NO;
}
return YES;
}

Related

Iphone should block 0 number in the keyboard

I've been writting iphone application in xcode, there is a form that contain phone number field. It must be contain 10 digits. If the user press 0 firstly in the keyboard, application must not write it.
For instance, phone number 05551234567, user can be only write 5551234567. If the user press 0, nothing happen.
First of all you should use
textView.keyboardType = UIKeyboardTypePhonePad
to choose the correct type of keyboard, so that you will be able to enter just numbers.
Secondly you must implement a UITextViewDelegate, set it as the text view delegate and implement a custom
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
that will check if you are trying to insert a 0 at the beginning of the content and return NO in that case.
If you are using a UITextField everything is the same, the only diffeference is that you will use UITextFieldDelegate and implement
- (BOOL)textField:(UITextField *)textField shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
Try following method.
by using below method user cannot enter 0 in textfield
- (BOOL)textField:(UITextField *)TextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:#"123456789"];
for (int i = 0; i < [string length]; i++)
{
unichar c = [string characterAtIndex:i];
if (![myCharSet characterIsMember:c])
{
return NO;
}
}
return YES;
}
And if you want that user cannot enter 0 only first place then use method like below
- (BOOL)textField:(UITextField *)TextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:#"123456789"];
if ([TextField.text length]<=0)
{
for (int i = 0; i < [string length]; i++)
{
unichar c = [string characterAtIndex:i];
if (![myCharSet characterIsMember:c])
{
return NO;
}
}
}
return YES;
}
I hope this will help you.

Adding a method to my uitextfield in cell?

I am adding this Method to my code to format the textfield. I am using the code below to try and add the method, but it not working, what am I doing wrong?
.h file
NSString* phone_;
UITextField* phoneFieldTextField;
#property (nonatomic,copy) NSString* phone;
.m file
#synthesize phone = phone_;
ViewDidLoad{
self.phone = #"";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
// Make cell unselectable and set font.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont fontWithName:#"ArialMT" size:13];
if (indexPath.section == 0) {
UITextField* tf = nil;
switch ( indexPath.row ) {
case 3: {
cell.textLabel.text = #"Phone" ;
tf = phoneFieldTextField = [self makeTextField:self.phone placeholder:#"xxx-xxx-xxxx"];
phoneFieldTextField.keyboardType = UIKeyboardTypePhonePad;
[self formatPhoneNumber:phoneFieldTextField.text deleteLastChar:YES];
[cell addSubview:phoneFieldTextField];
break ;
}
// Textfield dimensions
tf.frame = CGRectMake(120, 12, 170, 30);
// Workaround to dismiss keyboard when Done/Return is tapped
[tf addTarget:self action:#selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
}
}
// Textfield value changed, store the new value.
- (void)textFieldDidEndEditing:(UITextField *)textField {
//Section 1.
if ( textField == nameFieldTextField ) {
self.name = textField.text ;
} else if ( textField == addressFieldTextField ) {
self.address = textField.text ;
} else if ( textField == emailFieldTextField ) {
self.email = textField.text ;
} else if ( textField == phoneFieldTextField ) {
self.phone = textField.text ;
}else if ( textField == dateOfBirthTextField ) {
self.dateOfBirth = textField.text ;
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* totalString = [NSString stringWithFormat:#"%#%#",textField.text,string];
// if it's the phone number textfield format it.
if(textField.tag == 10 ) {
if (range.length == 1) {
// Delete button was hit.. so tell the method to delete the last char.
textField.text = [self formatPhoneNumber:totalString deleteLastChar:YES];
} else {
textField.text = [self formatPhoneNumber:totalString deleteLastChar:NO ];
}
return false;
}
return YES;
NSLog(#"Testing should change character in range");
}
-(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar {
if(simpleNumber.length == 0) return #"";
// use regex to remove non-digits(including spaces) so we are left with just the numbers
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[\\s-\\(\\)]" options:NSRegularExpressionCaseInsensitive error:&error];
simpleNumber = [regex stringByReplacingMatchesInString:simpleNumber options:0 range:NSMakeRange(0, [simpleNumber length]) withTemplate:#""];
// check if the number is to long
if(simpleNumber.length>10) {
// remove last extra chars.
simpleNumber = [simpleNumber substringToIndex:10];
}
if(deleteLastChar) {
// should we delete the last digit?
simpleNumber = [simpleNumber substringToIndex:[simpleNumber length] - 1];
}
// 123 456 7890
// format the number.. if it's less then 7 digits.. then use this regex.
if(simpleNumber.length<7)
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d+)"
withString:#"($1) $2"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
else // else do this one..
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d{3})(\\d+)"
withString:#"($1) $2-$3"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
if (simpleNumber.length == 10 && deleteLastChar == NO) { [self resignFirstResponder];}
return simpleNumber;
NSLog(#"Testing format phone number");
}
#pragma mark - TextField
-(UITextField*) makeTextField: (NSString*)text
placeholder: (NSString*)placeholder {
UITextField *tf = [[UITextField alloc] init];
tf.placeholder = placeholder;
tf.text = text ;
tf.autocorrectionType = UITextAutocorrectionTypeNo ;
tf.autocapitalizationType = UITextAutocapitalizationTypeNone;
tf.adjustsFontSizeToFitWidth = YES;
tf.returnKeyType = UIReturnKeyDone;
tf.textColor = [UIColor colorWithRed:56.0f/255.0f green:84.0f/255.0f blue:135.0f/255.0f alpha:1.0f];
return tf ;
}
The method you are using:
-(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar
Returns an NSString Object. In your case you are calling the method correctly but you are not setting the Returned NSString object to anything. It is simply hanging there. You need to set the phoneFieldTextField to the formatted text like so:
phoneFieldTextField.text = [self formatPhoneNumber:phoneFieldTextField.text deleteLastChar:YES];
NOTE - If you want to learn more about return methods then read the following:
If you noticed some most methods are of the void type. You know this when you see a method like this:
- (void)someMethod {
int x = 10;
}
What void means is that the someMethod does not return anything to you. It simply executes the code within the method. Now methods than return an object or some other data type look like this:
- (int)returnSomething {
int x = 10;
return x;
}
First thing you will notice is the return type is no longer void, it is an int. This means the method will return an integer type. In this case the code executes and you are returned the value of x.
This is just the start of the topic of return methods but hopefully it makes things a bit clearer for you.
First off you need to tell us What is not working we don't have your app and all your code. You need to explain what is working and what is not working exactly. It took longer then necessary to figure out that your question is why is textField:shouldChangeCharactersInRange: not working. Did you set a breakpoint in the function to see what it was doing. Was it not being called?
That said your bug is that textField:shouldChangeCharactersInRange: is using tags to identify text fields but the rest of the code is using pointers
// if it's the phone number textfield format it.
- if(textField.tag == 10 ) {
+ if(textField.tag == phoneFieldTextField ) {
Also you didn't include the code for makeTextField:placeholder: There could be issues in it too. Compare your code to the makeTextField:placeholder: in my sample.
I created a sample project on GitHub. To fix this. I also demos a better approach to creating input forms using table views.
https://github.com/GayleDDS/TestTableViewTextField.git
Look at both diffs to see what I did to YourTableViewController.m to make things work.
https://github.com/GayleDDS/TestTableViewTextField/commit/d65a288cb4da7e1e5b05790ea23d72d472564793
https://github.com/GayleDDS/TestTableViewTextField/commit/31ecaec8c9c01204643d72d6c3ca5a4c58982099
There is a bunch of other Issues here:
You need to call [super viewDidLoad]; in your viewDidLoad method
You need to correctly indent your code (could be a cut and paste issue)
You should be using the storyboard to create your views. See the better solution tab and BetterTableViewController implementation.
Must Watch - iOS Development Videos
WWDC 2011 - Session 309 - Introducing Interface Builder Storyboarding
https://developer.apple.com/videos/wwdc/2011/?id=309
Stanford iPhone Programing Class (Winter 2013)
Coding Together: Developing Apps for iPhone and iPad
https://itunes.apple.com/us/course/coding-together-developing/id593208016
Lecture 9. Scroll View and Table View
Lecture 16. Segues and Text Fields
Looks like you are not setting the delegate <UITextFieldDelegate> in the .h file, and not assigning your textfield's delegate property to self tf.delegate = self; in order to call - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Try that and let me know how it goes
-Good Luck!
#koray was right: you need to setup the delegate for the class. Your class should be declared as implementing the protocol UITextFieldDelegate (in addition to UITableViewDataSource, I assume)
then in your makeTextField: (NSString*)text placeholder: (NSString*)placeholder method, you need to have something like:
-(UITextField*) makeTextField: (NSString*)text
placeholder: (NSString*)placeholder {
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(40, 0, 150, 40)];
tf.placeholder = placeholder;
// (...)
tf.delegate = self;
return tf ;
}
Then you need to setup the delegate methods correctly. In the following example, I have a nav bar, since the numbers pad doesn't have a return or a done button. I setup a button that will act as the done button (you may have another way of making the keyboard go, and switching between text fields will trigger the end of edition anyway):
- (void) textFieldDidBeginEditing:(UITextField *)textField {
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneEditing:)];
self.navBar.topItem.rightBarButtonItem = doneBtn;
}
- (void) doneEditing:(id) sender {
if(phoneFieldTextField.isFirstResponder) {
[phoneFieldTextField resignFirstResponder];
}
// (...)
self.navBar.topItem.rightBarButtonItem = nil;
}
Then, the magic happens in the textDidEndEditing delegate method:
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ( textField == phoneFieldTextField ) {
self.phone = [self formatPhoneNumber:textField.text deleteLastChar:YES] ; // convert
[phoneFieldTextField setText:self.phone]; // display
}
// (...)
}

Moving the focus of a textfield to another based on conditions

I have 10 textfields, each of which could hold at most one character. When I enter a character in the first textfield, the focus should automatically move to the next textfield and so on. That is, as soon as the first character is entered in a textfield, the focus should shift to the next. That is, the next textfield should become the first responder. I have written the below code, used the textfield delegate method.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"];
for (int i = 0; i < [string length]; i++) {
unichar c = [string characterAtIndex:i];
if([myCharSet characterIsMember:c])
{
int previousTag = textField.tag;
if([textField.text length] > 0)
{
if((previousTag == 9) && ([textField10.text length] >0))
{
return NO;
}
UITextField *tempField=(UITextField *)[self.view viewWithTag:previousTag+1];
if([tempField.text length] > 0){
[tempField resignFirstResponder];
return NO;
}
[tempField becomeFirstResponder];
return YES;
}
}
else{
return NO;
}
}
return YES;
}
But I am not getting the desired results. When I type a character its entered in the first textfield, but the focus is not shifting to the next, though when I type the 2nd character, it is entered in the next textfield.
Similarly, I need to write a delete function such that when I delete a textfield, the focus automatically shifts to the previous textfield.
Any answers will be appreciated. Thanks.
You can always return NO and change the textField text manually. I guess what you need is something like this.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"];
int previousTag = textField.tag;
if ([string isEqualToString:#""]) {//backspace button
if (previousTag==0) {//added to prevent crashing in first tf
return YES;
}
UITextField *tempField2=(UITextField *)[self.view viewWithTag:previousTag-1];
textField.text=string;
[tempField2 becomeFirstResponder];
return NO;
}
for (int i = 0; i < [string length]; i++) {
unichar c = [string characterAtIndex:i];
if([myCharSet characterIsMember:c])
{
if((previousTag == 9) && ([textField10.text length] >0))
{
return NO;
}
UITextField *tempField=(UITextField *)[self.view viewWithTag:previousTag+1];
if([tempField.text length] > 0)
{
textField.text=string;
[tempField resignFirstResponder];
return NO;
}
textField.text=string;
[tempField becomeFirstResponder];
return NO;
}
else{
return NO;
}
}
return YES;
}
-shouldChangeCharactersInRange gets called before text field actually changes its text. So you will be getting the old value in the string. Add the line at the beginning of your method. It should fix your problem.
string = [textField.text stringByReplacingCharactersInRange:range withString:string];

setting max capacity to a UITextField

hi
i am using a series of textfields in a row in my application and my requirement is the textfield should accept only one character.if a user enters second character no action should be performed.
i implemented the delegate method as below
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
if ([cellTextField.text length]>=MAXLENGTH && range.length==0) {
textField.text=[cellTextField.text substringToIndex:MAXLENGTH-1];
return NO;
}
else {
return YES;
}
but my requirement is not being filled using the above code.
my next requirement is if a user continues entering a second character, the character should be placed in the consecutive textField(imagine crossword or scramble application). please help me in both scenarios if possible else solution for first requirement is also thankful.
thank you,
dinakar
The following code solved this for me.
Make sure you check for the "\b" (Backspace escape character) so that the user can still erase.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if ([textField.text length] >= MAXLENGTH && ![string isEqualToString:#"\b"])
return NO;
return YES;
}
As far as your second requirement goes it's really not too hard. Just add a few lines of code into the above if-statement:
nextTextField.text = [nextTextField.text stringByAppendingString:string];
This should add whatever text you just typed in to the end of your next text field. You might also want to change the way backspace is handled. Something like:
if ([string isEqualToString:#"\b"])
nextTextField.text = [nextTextField.text substringToIndex:[nextTextField.text length]-1];
Adding that code inside the above if statement as well should allow you to delete the character at the end of the complete string (at the end of the string in the next text field).
EDIT: Here's the code I use to create the field.
titleInput = [[UITextField alloc] initWithFrame:(CGRect){40,145,400,30}];
titleInput.borderStyle = UITextBorderStyleRoundedRect;
titleInput.delegate = self;
[self addSubview:titleInput];
Cheers
if(cellTextField.text.length >= MAXLENGTH)
{
[cellTextField2 becomeFirstResponder]
}
This sets the focus to be the second text field
check in below functions for the number of character in your UITextField;
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
if the number of character in you text field is more than one just return NO;
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(mytextField1 == textField && [mytextField1.text length] >= 1)
{
[mytextField1 becomeFirstResponder];
return NO;
}
else if(mytextField2 == textField && [mytextField2.text length] >= 1)
{
[mytextField3 becomeFirstResponder];
return NO;
}
-------------------------------
-------------------------------
else if(mytextField8 == textField && [mytextField8.text length] >= 1)
{
[mytextField1 becomeFirstResponder];
return NO;
}
return YES;
}

User input in UITextView call delegate method twice?

I want to compare a string with user input character by character. e.g. I want to let user input "I have an apple." and compare the input with this string to see if his input is correct. When he input a wrong character, iphone will vibrate to inform him immediately. The problem is that I find some characters like the space will call the delegate method twice- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
When I press the space key, the first time I compare the text with the ' ', the result will show me that they're the same character. But after that, I have to advance the index of string character to the next. And the second time the delegate method is called, iphone will vibrate. Any ideas about how to solve this problem?
Here is my code:
strText = #"I have an apple.";
index = 0;
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSRange rg = {index, 1};
NSString *correctChar = [strText substringWithRange:rg];
if([text isEqualToString:correctChar])
{
index++;
if(index == [strText length])
{
// inform the user that all of his input is correct
}
else
{
// tell the user that he has index(the number of correct characters) characters correct
}
}
else {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
return NO;
}
return YES;
}
try this
- (void)textViewDidChange:(UITextView *)textView{
if(![myStringToCompareWith hasPrefix:textView.text]){
//call vibrate here
}
}
Building on Morion's suggestion of using hasPrefix:, I think this is the solution that you are looking for:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// create final version of textView after the current text has been inserted
NSMutableString *updatedText = [NSMutableString stringWithString:textView.text];
[updatedText insertString:text atIndex:range.location];
if(![strTxt hasPrefix:updatedText]){
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
return NO;
}
return YES;
}