How do I get the line height of UITextField - ios

I have a few questions that I can't find the answers online:
1.How do I get the line height of UITextField?
2.How do I get UITextField to only enter a maximum of 3 lines of text?
3.How do I get UITextField to only enter a maximum of 25 characters per line?
and thanks for answer!

As the comment says, you should use UITextView, not UITextField.
UITextField handles only a single line.
Use UITextView to process multiple lines of text.
I'm going to give you an opinion on number 3.
First, there is something that limits the length of the textview.
Auto-layout to a length of 25 characters to fit the font size you want.
The second is that when the text reaches 25 characters, it adds a line-breaking symbol.
extension mainVC: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if let char = text.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if isBackSpace != -92 {
if textView.text.count == 25 {
textView.text += "\n"
}
}
}
return true
}
}
If what you entered is not backspace, it will be executed. If it's 25 characters, you can add the line symbol '\n' to the text in textView and change it.

Related

How to allow CollectionViewCell textfield with all character in capital letter with character limit 1 in iOS Swift 3?

I want to allow CollectionViewCell textfield with all character(only alphabates) in uppercase with character limit 1 if user enter lowercase textfield convert it into uppercase in iOS Swift 3 ?
In Swift 3, 4:
First add this line of code. It will Capitalized you keyboard.
yourTextField.autocapitalizationType = .allCharacters
Then set delegate to your desired textfield like that
yourTextField.delegate = self
Now implement this delegate method of textfield. This method listen your keypress.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// check your char limit here & capitalized char based on your requirement.
yourTextField.text = textField.text?.uppercased()
return true
}
Hope it helps.
yourTextfield.autocapitalizationType = .allCharacters
for character limit you can refer this : Max length UITextField

Emojis breaking my code in UItextView Swift 4

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if range.length + range.location > commentView.text!.count{
return false
}
let newLength = (commentView.text?.count)! + text.count - range.length
let i = charCount - newLength
if i < 30 {
charCountLabel.textColor = UIColor.red
} else {
charCountLabel.textColor = UIColor(r: 79, g: 79, b: 79)
}
charCountLabel.text = "\(i)"
return newLength < charCount
}
The above code is a character counter for a UITextView, yet when I enter a single emoji into the UITextView the editing stops, why is that?? and how would I integrate a fix
CommentView : UItextView
charCount : Int
charCountLabel : UIlabel
sc of the debugger
upon stepping though the thread I get this when I try to send another character :
further in thread
EDIT
upon going through the debugger I have found that the second emoji or any char is causing the "I" var to be some super long number same with the "newLength" ... any one got any ideas?
I tried running your code in a test project and hit several issues. I assumed you initialized 'charCount' with 0 to begin, but this results in 'i' being -1 when you type the first character, which then returns false for every character after that.
If you're simply trying to implement a text length counter there are easier ways to do it. The two methods below populate the proper character count in the counter label when adding/deleting regular text and emoji characters.
First method I'd try is implementing the textView delegate func textViewDidChange(_ textView: UITextView). This will update the label count after every character you type. You could also set your text color here if you want.
func textViewDidChange(_ textView: UITextView) {
// only want to update character count label for commentView
guard textView == commentView, let string = textView.text else {
return
}
// update counter label text with the current text count of the textview
charCountLabel.text = "\(string.count)"
}
The second method is to use the textView delegate you were using. Here's some code I got working in a test project. There are probably better ways than this but this will get you going.
#IBOutlet weak var commentView: UITextView!
#IBOutlet weak var charCountLabel: UILabel!
let minCount = 30
let maxCount = 120
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// only want to update character count label for commentView
guard textView == commentView, let string = textView.text else {
return true
}
// get current text + new character being entered
var newStr = string+text
// check if this is a backspace
let isDeleting = (range.length > 0) && text.isEmpty
if isDeleting == true {
// trim last character
// you may want to drop based on the range.length, however you'll need
// to determine if the character is an emoji and adjust the number of characters
// as range.length returns a length > 1 for emojis
newStr = String(newStr.dropLast())
}
// set text color based on whether we're over the min count
charCountLabel.textColor = newStr.count < minCount ? .red : .blue
// set the character count in the counter label
charCountLabel.text = "\(newStr.count)"
// if we're less than the max count allowed, return true
return newStr.count < maxCount
}

In Swift, how do I detect a double tap from the spacebar in UITextView?

I'm working on an app that is heavily dependent on a UITextView. The desired behavior is when a user double taps the spacebar, the cursor will indent 5 spaces. How would I do this?
You should use a timer which checks for short time intervals and the shouldChangeTextInRange delegate method for UITextView and write a condition for space strings. After that, you can use the insertText method of UITextInput, one of UITextView's protocols:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == " " {
if isSecondSpace {
(textView as UIKeyInput).insertText(" ") //5 spaces
} else {
isSecondSpace = true
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) {
self.isSecondSpace = false
}
}
return false
}
return true
}
Use the UIText​View​Delegate and in the text​View(UIText​View, should​Change​Text​In:​ NSRange, replacement​Text:​ String) function you keep track of the space inputs and the times. When you receive two space inputs within a short time frame, you manipulate the textfield with the 5 spaces.

If i wanted to change the color of a specific word entered in textview, How would i do that?

From what i've read i would need to use rangeOfString to search a textview entry but am unsure about how to go about that. Is it possible to change the color of a text entered in textview in real time, for example if someone wrote "blue," could i change the word to blue the moment they typed it. If so how would i go about that? I'm very new to coding and even newer to swift.
You will have to use attributed text for your text view and then use the textView(textView: UITextView, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool method, which will be triggered whenever the text in the text view's text changes. Apply your own logic in there as to what range the colored text will fall into and how that will happen...
Make sure your controller conforms to the UITextViewDelegate protocol and make the textView's delegate your controller.
Demonstration:
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.delegate = self // important! Otherwise the textView will not know where to call the delegate functions!
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// first make sure that the text field is the one we want to actually change
if textView == self.textView{
let nsString = textView.text as NSString // we explicitly cast the Swift string to NSString so that we can use rangeOfString for example
let stringLength = textView.text.characters.count
// Arbitrarily check if the string in the text field is not empty
// Apply your own logic for when to update the string
if stringLength > 0{
let text = NSMutableAttributedString(string: textView.text)
// Currently the range is assumed to be the whole text (the range covers the whole string)
// You'll have to apply your own logic here
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, stringLength))
textView.attributedText = text
}
}
return true
}
}
For example, instead of using the above to color the whole text
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, stringLength))
Color the first occurence of "hello" in red:
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: nsString.rangeOfString("hello"))
Note that I explicitly cast the textView's text to NSString so that we can use the range functions such as (rangeOfString())
Changes were made to swift in which count no longer seems to work with String. I made a slight change to the answer given by the_critic (https://stackoverflow.com/users/1066899/the-critic). Thank you to all who helped
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.delegate = self // important! Otherwise the textView will not know where to call the delegate functions!
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// first make sure that the text field is the one we want to actually change
if textView == self.textView{
let nsString = textView.text as NSString // we explicitly cast the Swift string to NSString so that we can use rangeOfString for example
let stringLength = textView.text.characters.count
// Arbitrarily check if the string in the text field is not
empty
// Apply your own logic for when to update the string
if stringLength > 0{
let text = NSMutableAttributedString(string: textView.text)
// Currently the range is assumed to be the whole text (the range covers the whole string)
// You'll have to apply your own logic here
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, stringLength))
textView.attributedText = text
}
}
return true
}
}

Uppercase characters in UItextfield

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?
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
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
}
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.
The syntax is now
Swift 2
textField.autocapitalizationType = UITextAutocapitalizationType.AllCharacters
Swift 3
textField.autocapitalizationType = .allCharacters
This is a different approach I used, where it does the following:
Enforces capitalization as soon as the character is entered
Catches situations where the user disables caps lock even if it textfield is set to auto caps
Allows for easy editing
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.
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()
}
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
Set UITextField property autocapitalizationType to UITextAutocapitalizationTypeAllCharacters. This will make all characters to appear in upper case. Also visit here to find more about textfields
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.
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
}
}
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;
}
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];
}
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
}
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!
/**
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
}
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".
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
}
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.

Resources