How do I force characters input into a textbox on the iPhone to upper case?
Set autocapitalizationType to UITextAutocapitalizationTypeAllCharacters on the UITextField.
See UITextInputTraits protocol (adopted by UITextField) for more details.
This solution is not fully satisfying.
Even with the autocapitalizationType set to UITextAutocapitalizationTypeAllCharacters, the user can still press caps to release the caps lock. And the textField.text = [textField.text stringByReplacingCharactersInRange:range withString:[string uppercaseString]]; return NO; solution is not that great: we loose the editing point if the user edits the middle of the text (after a textField.text =, the editing cursor goes to the end of the string).
I've done a mix of the two solution and here is what I propose: set UITextAutocapitalizationTypeAllCharacters, and add the following code to the delegate of the UITextField.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
// Check if the added string contains lowercase characters.
// If so, those characters are replaced by uppercase characters.
// But this has the effect of losing the editing point
// (only when trying to edit with lowercase characters),
// because the text of the UITextField is modified.
// That is why we only replace the text when this is really needed.
NSRange lowercaseCharRange;
lowercaseCharRange = [string rangeOfCharacterFromSet:[NSCharacterSet lowercaseLetterCharacterSet]];
if (lowercaseCharRange.location != NSNotFound) {
textField.text = [textField.text stringByReplacingCharactersInRange:range
withString:[string uppercaseString]];
return NO;
}
return YES;
}
While all the other answers do actually work (they make the input uppercase), they all have the problem that the cursor position is not retained (try inserting a character in the middle of the existing text). This apparently happens in the setter of UITextField's text property, and I have not found a way to restore it programmatically (for example, restoring the original selectedTextRange does not work).
However, the good news is, that there is a direct way to replace parts of a UITextField's (or UITextView's) text, which does not suffer from this issue:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// not so easy to get an UITextRange from an NSRange...
// thanks to Nicolas Bachschmidt (see http://stackoverflow.com/questions/9126709/create-uitextrange-from-nsrange)
UITextPosition *beginning = textField.beginningOfDocument;
UITextPosition *start = [textField positionFromPosition:beginning offset:range.location];
UITextPosition *end = [textField positionFromPosition:start offset:range.length];
UITextRange *textRange = [textField textRangeFromPosition:start toPosition:end];
// replace the text in the range with the upper case version of the replacement string
[textField replaceRange:textRange withText:[string uppercaseString]];
// don't change the characters automatically
return NO;
}
For further information on these methods, see the documentation of UITextInput.
Rather than test for whether the character is upper- or lower-case, just assume that it's lower case. Much simpler.
In the
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
method:
NSString *newString = [[textField.text stringByAppendingString:string] uppercaseString];
textField.text = newString;
return NO;
The simplest way would be to , implement the editing changed method of the text field and set the textfield's text value to upper case representation of the entered text
- (IBAction)TextFieldEditingChanged:(id)sender
{
_yourTextField.text = [_yourTextField.text uppercaseString];
}
I've been inspired by previous answers (thanks), but all of them had some flaws for me:
using textField.autocapitalizationType does not help when you also want lowercase or even more control.
textField.text = "my String" sets the cursor to the end of the textField which is really annoying when editing.
So this is my Swift code that gives you full control over the typed characters (uppercase, lowercase, ignore...) AND lets the cursor where you expect it. The code is tested to work with more than one textField.
Edit: tested with iOS 8.3
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// modify string as and if the user wants:
// at this place you can also return false to ignore the replacement completely.
var str = string
if !Defaults.isUpperOrLower() {
if Defaults.isAllLetterUpper() {
str = string.uppercaseString
} else {
str = string.lowercaseString
}
}
// updating textField.text sets the curser position to the end
// so we store the cursor position before updating.
let selRange = textField.selectedTextRange
// Update textField as requested and modified.
var txt = textField.text as NSString
textField.text = txt.stringByReplacingCharactersInRange(range, withString: str)
// recalculate and set the cursor position in the textField:
// tested with
// 1. typing a character
// 2. backspace
// 3. selecting a range + backspace
// 4. selecting a range + typing a character
if let selRange = selRange {
var newPosition: UITextPosition?
if range.length == 0 {
// normal character
newPosition = textField.positionFromPosition(selRange.end, inDirection: UITextLayoutDirection.Right, offset: count(string))
} else {
// backspace
newPosition = textField.positionFromPosition(selRange.end, inDirection: UITextLayoutDirection.Left, offset: range.length - count(string))
}
textField.selectedTextRange = textField.textRangeFromPosition(newPosition, toPosition: newPosition)
}
// return false because we did everything manually
return false
}
This is my code, when i have 6 textFields
Hope you will get the point
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField==self.textField6) {
self.textField6.text = [textField.text stringByReplacingCharactersInRange:range withString:[string uppercaseString]];
return NO;
}
return YES;
}
return NO will have issues with back button;
beter use this
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if ([[string uppercaseString] isEqualToString:string]) {
return YES;
}
NSString *newString = [[textField.text stringByAppendingString:string] uppercaseString];
textField.text = newString;
return NO;
}
Maybe I haven't found all the kinks to this method, but so far it works well for me. It seems to avoid the issues with jumping selection to the end if you go down the route of returning NO from -textField:shouldChangeCharactersInRange:replacementString:. Since UITextField conforms to UIKeyInput, simply override the method -insertText: to change the input string to uppercase before calling super with the uppercase string:
- (void)insertText:(NSString *)text {
NSString *uppercaseText = [text uppercaseString]
[super insertText:uppercaseText]
}
Or if you've moved along to Swift:
override func insertText(text: String) {
let uppercaseText = text.uppercaseString
super.insertText(uppercaseText)
}
To Automatically input uppercase in textfield:
Case 1: Add UITextDelegate protocol and implement the following method
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
textField.text = [textField.text stringByReplacingCharactersInRange:range withString:[string capitalizedString]];
return NO;
}
Case 2:Set the following parameter in the ViewDidLoad() method in your view controller. Although in this case the user can turnoff the caps button on the keyboard.
urTextFieldName.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
One issue I have with some of the above answers is if you try and set textfield.text, you will lose the cursor position. So if a user tries to edit the middle of the text, the cursor will jump to the end.
Here is my simple Swift solution, still using UITextFieldDelegate:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField == textFieldToUppercase {
if string == "" {
// User presses backspace
textField.deleteBackward()
} else {
// User presses a key or pastes
textField.insertText(string.uppercaseString)
}
// Do not let specified text range to be changed
return false
}
return true
}
You still have to handle if a user presses the Return, Done, etc key on the keyboard. Just add:
if string == "\n" {
// Do something when 'Done' is pressed, like dismiss the keyboard
textField.resignFirstResponder()
return false
}
...inside of func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool.
Related
i am trying to get total value after multiplying price and quantity in to text field. I not getting value when quantity is 10 or having any two or three digits.This method takes only one character at time.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
if(textField == quantityText)
{
NSCharacterSet *charactersToRemove =[[ NSCharacterSet alphanumericCharacterSet ]
invertedSet];
NSRange inRange=[string rangeOfCharacterFromSet:charactersToRemove];
if(inRange.location != NSNotFound)
{
quantityText.text =[ quantityText.text
stringByTrimmingCharactersInSet:charactersToRemove ];
return NO;
}
if ([textField text] )
{
float quantity = [string floatValue];
float price = [[priceLabel text] floatValue];
float h = quantity * price;
amountText.text=[NSString stringWithFormat:#"%f",h];
}
else
{
return NO;
}
}
return YES;
}
You're only using the replacementString value for your calculation, which is the last character that was typed, not the whole the whole string.
So if I type '1' then function uses 1 as the value, then if I type '0' to make 10, your function only uses the '0' as the value.
You need to get the whole text of the quantityText textfield and use that. You could get that by taking textField.text and then replacing the specified range with the replacementString.
To be honest though it's a lot easier just to register for the UITextFieldTextDidChangeNotification instead of using the textfield:shouldChangeCharactersInRange:replacementString: method.
See this answer for details.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
this delegate method is called whenever user types a new character in to the textfield and the string object will contain only the last typed character. so instead of using (NSString *)string use textField.text
I want to apply validation on text field. I have two text filed and i want to enter only 0-11 value when second text field value is equal to "AM". How apply validation text filed with respect to another text field's value?
Thanks in advance...
You can achieve your design by keeping references to both text fields in your view controller.
However, it would be much more conforming to Apple's Human Interface Guidelines to use a UIPickerView for choosing from a number of items less than 12.
try this way
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField{
if(textField==self.txt1 && [self.txt2.text isEqualToString:#"AM"]){
[self.txt1 setKeyboardType:UIKeyboardTypeNumberPad];
}
return YES;
}
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if ([string isEqualToString:#""]) {
return YES;
}
if(textField==self.txt1 && [self.txt2.text isEqualToString:#"AM"]){
int no=[self.txt1.text intValue];
NSLog(#"%d",no);
int enteredno=[string intValue];
int sum=no*10+enteredno;
if (sum>11) {
return NO;
}
}
return YES;
}
Here txt1 and txt2 are first and second textfields. Set the delegate to both the textfields.
get the value from second textfiled and check then validate like
if([secTxtField.text isEqualToString:#"AM"])
{
//do the validation for the first
}
first check for only numbers here,
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
static NSCharacterSet *charSet = nil;
if(!charSet) {
charSet = [[[NSCharacterSet characterSetWithCharactersInString:#"0123456789"] invertedSet] retain];
}
NSRange location = [string rangeOfCharacterFromSet:charSet];
if(!(location.location == NSNotFound))
{
if([secTxtField.text isEqualToString:#"AM"])
{
//get the first textField input
//Conver to int
//Check for less than 11
if (pass)
{
return YES;
}
else
{
return NO;
}
}
}
return (location.location == NSNotFound);
}
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;
}
}
I have an UITextField and I would like that for every tap on a character, the first character is deleted. So that I just have one character in my textField every time. Moreover I would like it to display every tap in the console log.
How can I do this?
You need to implement shouldChangeCharactersInRange method in your text field delegate:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:
(NSRange)range replacementString:(NSString *)string{
textField.text = #"";
return YES;
}
You may need to check for range and string values to cover all possible cases (like copy/paste actions). This code just sets the text field's value to the last typed character.
UITextField inherits from UIControl, so you can use the target-action mechanism that is part of the UIControl class:
[textField addTarget:self action:#selector(updateTextField) forControlEvents:UIControlEventValueChanged];
In the action method, you can replace the UITextField's text with only the last character and log that character in the console. Note that since changing the UITextField's text will again result in the "updateTextField" message being sent a second time to the target, you will need some kind of mechanism for determining whether to update or not:
- (void)updateTextField {
if(updateTextField == YES) {
updateTextField = NO;
NSString *lastChar = [textField.text substringFromIndex:[textField.text length]];
[textField setText:lastChar];
NSLog(#"%#", lastChar);
} else {
updateTextField = YES;
}
}
Or something like that anyway...
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField.text.length > 8) {
return NO;
}
return YES;
}
i want to let the user type in the name of a new file, so there are certain characters i want to prevent entry on. is there a special keyboard i can use or can i disable certain keys on the iphones keyboard.
is the answer to just run a regular expression on the input text and tell the user the filename is invalid (if so what would that regular expression be?)
ANSWER: (or what i ended up doing)
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
BOOL valid;
//if the user has put in a space at the beginning
if ([string isEqualToString:#" "]){
if (range.location == 0){
valid = NO;
}
else{
valid = YES;
}
}
//otherwise test for alpha numeric
else{
NSCharacterSet *alphaSet = [NSCharacterSet alphanumericCharacterSet];
valid = [[string stringByTrimmingCharactersInSet:alphaSet] isEqualToString:#""];
}
//print the warning label
if (valid == NO){
[errorLabel setText:#"Invalid input"];
}
else{
[errorLabel setText:nil];
}
return valid;
}
You can implement the delegate method
For UITextField,
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
For UITextview
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
and decide weather to append the entered characters or not.
You can implement the UITextFieldDelegate protocol and use textField:shouldChangeCharactersInRange:replacementString: to watch the text entry and prevent unwanted characters by returning NO.