68

I have a question about iOS UIKeyboard.

I have a UITextField and I would to have the keyboard with only uppercase characters.

I use a storyboard and I tried to set the Cpitalization as "All characters" to UITextField properties.

But this not solve my problem...any suggestion?

Sport
  • 8,570
  • 6
  • 46
  • 65
Safari
  • 11,437
  • 24
  • 91
  • 191

18 Answers18

116

Set your textfield type autocapitalizationType to UITextAutocapitalizationTypeAllCharacters on the UITextField

self.yourTexField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;

After call delegate

// delegate method

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSRange lowercaseCharRange = [string rangeOfCharacterFromSet:[NSCharacterSet lowercaseLetterCharacterSet]];

    if (lowercaseCharRange.location != NSNotFound) {
        textField.text = [textField.text stringByReplacingCharactersInRange:range
                                                                 withString:[string uppercaseString]];
        return NO;
    }

    return YES;
}

Swift 5.4.2

       self.yourTextField.autocapitalizationType = .allCharacters
codercat
  • 22,873
  • 9
  • 61
  • 85
  • This won't work for pasting text since `string` can have multiple lowercase characters. – chrisamanse Oct 16 '16 at 02:43
  • My bad, your code works. I thought the code only uppercases the found lowercase character. `[string uppercaseString]` uppercases all the characters. – chrisamanse Oct 19 '16 at 06:23
  • 2
    This is no good, because if the user enters text in the middle of the text, the selection suddenly jumps to the end of the text. – matt Oct 02 '17 at 00:32
  • @matt check out my solution https://stackoverflow.com/a/54634230/4600723 I have found the way how to keep cursor at the user's position. – Marek Staňa Feb 11 '19 at 15:49
  • Note: This will cause cursor to jump to end of text field if you were in middle. Track, adjust, and set the selected range using code found here: https://stackoverflow.com/q/26284271/2057171 --- secondary note: not sure how ranges work with rightToLeft languages – Albert Renshaw Jun 07 '20 at 03:05
28

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 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
}
Dan
  • 289
  • 4
  • 3
  • 7
    This answer should be _way_ upvoted (and accepted). All the other stuff on this page, setting the text field's `text` directly, is dead wrong. – matt Oct 02 '17 at 00:37
  • What is `textFieldToUppercase`? – Slaknation May 24 '19 at 14:08
  • 1
    @Slaknation this is a comparison to check if this is the right textField. Often, you would set the same delegate to more than one textField, so the function will be called for all textFields. – heyfrank Jul 25 '19 at 09:23
20

For those looking for a Swift version.

Swift 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.uppercased())

    return false
}

Original answer

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    textField.text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string.uppercaseString)

    return false
}

Using the Capitalization: All Characters property just forces keyboard to open with caps lock on, but lets the user to turned it off.

Viktor Sec
  • 2,756
  • 1
  • 24
  • 31
Tim S
  • 5,023
  • 1
  • 34
  • 34
18

The syntax is now

Swift 2

textField.autocapitalizationType = UITextAutocapitalizationType.AllCharacters

Swift 3

textField.autocapitalizationType = .allCharacters
pableiros
  • 14,932
  • 12
  • 99
  • 105
Eden
  • 1,782
  • 15
  • 23
  • 2
    This doesn't prevent the user from typing lowercase characters. It just sets the Capslock key on the keyboard. If the user taps on it, lowercase input is possible. – heyfrank Jul 25 '19 at 09:24
9

This is a different approach I used, where it does the following:

  1. Enforces capitalization as soon as the character is entered
  2. Catches situations where the user disables caps lock even if it textfield is set to auto caps
  3. Allows for easy editing
  4. Works with Swift 2.2

First, register a notification to be updated whenever any changes occur in the textfield.

    textField.addTarget(self, action: #selector(YourClassName.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged)

Then, implement textFieldDidChange.

func textFieldDidChange(textField: UITextField) {
    textField.text = textField.text?.uppercaseString
}

I chose this to avoid a situation where the user sees an uneven experience of some capitalized, but then changed once they move to the next character.

CodeBender
  • 35,668
  • 12
  • 125
  • 132
6

Swift 3 / Swift 4 / Swift 5

Just one line code in ViewDidLoad/ViewDidAppear:

If you simply want to see the characters typed regardless of the UPPER/lower case to all CAPITALS/UPPER CASE paste below code either in ViewDidLoad/ViewDidAppear

self.myTextField.autocapitalizationType = .allCharacters

above line changes all letters into CAPITALS while you type automatically

Community
  • 1
  • 1
vilas deshmukh
  • 389
  • 2
  • 5
  • 1
    This is the best solution! Thanks! – Ezequiel Santos Jan 07 '20 at 18:10
  • 2
    Not not the best in all settings. If setting the keyboard to all caps is all you need, this works. But the user can click the keyboard shift-key off, or they can copy & paste from another app. Also: note that this does the same thing as the textField's attribute inspector selection: "Text Input Traits" > Capitalization > All Characters. Achieves the same thing without code. For true all caps in all situations, see other options above. – Gallaugher May 08 '20 at 15:42
6

You should avoid to use delegate method

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool

because this will trigger an unwanted behaviour with iOS 13 + QuickPath typing (the iOS' Swiftkey Keyboard counterpart).

If you swipe on the keyboard and write "hello", it will write "HELLOHELLOHELLOHELLOHELLO" into the textfield. This is because the method is called multiple times and it appends the just changed text via textField.text = uppercasedValue.

The right way is to observe the .editingChange event and uppercase then the value. For example:

func awakeFromNib() {
    textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
}

and

@objc func textFieldDidChange() {
    textField.text = textField.text?.uppercased()
}
Enrico F.
  • 301
  • 3
  • 3
5

Set UITextField property autocapitalizationType to UITextAutocapitalizationTypeAllCharacters. This will make all characters to appear in upper case. Also visit here to find more about textfields

Adnan Aftab
  • 14,377
  • 4
  • 45
  • 54
  • 1
    I am using this and it doesn't do anything. Have you any idea why? – CarmenA Sep 23 '15 at 16:35
  • Just to make others aware, this approach does not prevent the user from entering lowercase characters if they disable caps lock on the keyboard. – Gordonium Feb 28 '20 at 10:58
  • "Some keyboard types do not support autocapitalization. Specifically, this option is ignored if the value in the keyboardType property is set to UIKeyboardType.numberPad, UIKeyboardType.phonePad, or UIKeyboardType.namePhonePad." – atineoSE Aug 24 '22 at 17:45
5

SwiftUI

For SwiftUI the Syntax for autocapitalization and Keyboard type selection is:

TextField("Your Placeholder", text: $emailAddress)
     .keyboardType(.emailAddress)
     .autocapitalization(.none)

You can use the following options for autocapitalization:

.none //Specifies that there is no automatic text capitalization.

.words //Specifies automatic capitalization of the first letter of each word.

.sentences //Specifies automatic capitalization of the first letter of each sentence.

.allCharacters //Specifies automatic capitalization of all characters, such as for entry of two-character state abbreviations for the United States.
Jonas Deichelmann
  • 3,513
  • 1
  • 30
  • 45
4

Swift 4.0 Version:

First set the delegate for the textfield you want to uppercase to the current ViewController (click drag from the textfield to the currentViewController to set the delegate).

After add the extension:

extension CurrentViewController: UITextFieldDelegate{

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        //refference to the textfield you want to target
        if textField.tag == 5{
            textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.uppercased())
            return false
        }
        return true
    }
}
Matias Contreras
  • 442
  • 5
  • 10
1

You can also use this code.

-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range     replacementString:(NSString *)string{

    // Uppercase for string which you need 
    textField.text = [textField.text stringByReplacingCharactersInRange:range 
                                 withString:[string uppercaseString]];

    // return NO because You have already done it in above code
    return NO;
}
Viet Nguyen
  • 2,285
  • 2
  • 26
  • 43
Linh Nguyen
  • 2,006
  • 1
  • 20
  • 16
1

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.

@property (nonatomic, strong) IBOutlet UITextField *yourTextfield

// add target in code or use interface builder
[self.yourTextField addTarget:self 
                       action:@selector(uppercaseTextField)
             forControlEvents:UIControlEventEditingChanged];

- (IBAction)uppercaseTextField:(UITextField*)textField
{
    textField.text = [textField.text uppercaseString];
}
Jason Moore
  • 7,169
  • 1
  • 44
  • 45
Omkar Guhilot
  • 1,712
  • 11
  • 17
1

Finally I found the way that respects also editing text in the middle of the string in UITextField.

The problem is that if you replace whole text by UITextFiled.text property the actual cursor moves to end of text. So you need to use .replace() method to specify exactly which characters you want to update to upperCase.

Last thing is to return string.isEmpty as return value of function - otherwise you are not allowing deleting of text.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if let text = textField.text, let textRange = Range(range, in: text) {
        let uppercasedString = string.uppercased()
        let updatedText = text.replacingCharacters(in: textRange, with: uppercasedString)
        if let selectedTextRange = textField.selectedTextRange {
            textField.replace(selectedTextRange, withText: uppercasedString)
            approveButtonState(vin: updatedText)
        }
        return string.isEmpty
    }
    return false
}
Marek Staňa
  • 522
  • 7
  • 10
  • Good, but I think you're working too hard. Just call `insertText`, as shown in https://stackoverflow.com/a/37717492/341994 – matt Feb 11 '19 at 15:57
0

Maybe it's a bit late for an answer here, but as I have a working solution someone might find it useful.

Well, in the following textfield delegate method, check if the new string contains any lowercase characters. If so, then:

  • Append the character that was just typed to the textfield's text.
  • Make all the textfield's text uppercased.
  • Make sure that false is returned by the method.

Otherwise just return true and let the method work as expected.

Here's its implementation:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    var returnValue = true
    let lowercaseRange = string.rangeOfCharacter(from: CharacterSet.lowercaseLetters)
    if let _ = lowercaseRange?.isEmpty {
        returnValue = false
    }

    if !returnValue {
        textField.text = (textField.text! + string).uppercased()
    }

    return returnValue
}

The above has worked perfectly for me, and a similar implementation works for textviews too, after making the proper adjustments first of course.

Hope it helps!

Gabb
  • 187
  • 2
  • 5
0
/**
 We take full control of the text entered so that lowercase cannot be inserted
 we replace lowercase to uppercase
*/
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    // No spaces allowed
    if string == " " {
        return false
    }

    // delete key pressed
    if string == "" {
        textField.deleteBackward()
        return false
    }

    // We only allow alphabet and numbers
    let numbersAndLettersSet = CharacterSet.alphanumerics
    if string.lowercased().rangeOfCharacter(from: numbersAndLettersSet) == nil {
        return false
    }

    // Add the entered text
    textField.insertText(string.uppercased())

    // Return false as we are doing full control
    return false
}
Chris
  • 2,739
  • 4
  • 29
  • 57
0

Here there's my situation and how I achieved to force the upper text:

  • custom class (UITextField subclass)
  • don't want to use delegate UITextFieldDelegate methods

Solution proposed from @CodeBender was pretty much what I was looking for but the cursor always jump to the end as noticed from @Dan.

class MyCustomTextField: UITextField {
...
addTarget(self, action: #selector(upperText), for: .editingChanged)
...
...
@objc private func upperText() {
    let textRange = selectedTextRange
    text = text?.uppercased()
    selectedTextRange = textRange
}

This will set the cursor always in the correct position (where it was) even if user adds text in "the middle".

magpie
  • 162
  • 2
  • 9
0

On text change we can change to uppercase

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if textField == txtEmail {
            textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.uppercased())
            return false
        }
        return true
    }
Neha
  • 666
  • 1
  • 10
  • 17
-1

Using the following text field delegate method it can be done:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
//--- Making uppercase ---//
        if (textField == yourTextField ) {
            NSRange lowercaseCharRange;
            lowercaseCharRange = [string rangeOfCharacterFromSet:[NSCharacterSet lowercaseLetterCharacterSet]];

            if (lowercaseCharRange.location != NSNotFound) {

                textField.text = [textField.text stringByReplacingCharactersInRange:range
                                                                         withString:[string uppercaseString]];
                return NO;
            }
        }


}

Hope this helps.

Nameet
  • 650
  • 8
  • 20