UITextField - uneditable prefixed characters both in beginning & end - ios

I have a UITextField, and I want to give it uneditable characters. For example I have "Hello...", and I want the user to write in between o and . such as "Hello userTypedStuff..."
I used this approach, however with that, user can longpress the beginning and for example go to the position inside Hello. Thus, user can mess with the prefixed characters.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let protectedRange = NSMakeRange(0, 5)
let intersection = NSIntersectionRange(protectedRange, range)
if intersection.length > 0 {
return false
}
if range.location == 12 {
return true
}
if range.location + range.length > 12 {
return false
}
return true
}
How can I setup something like 'uneditable first 5 characters and last 3 characters'?
Edit: The UITextField's text-aligned center and is forming above a UILabel. However, if I give textField the width of label, textField won't get larger on width. Thus, I gave its width view's width. Is there a way I can create UILabel on both ends having Hello and ... separately, and have textField (with text-aligned center) in the middle which automatically stretches width?
Edit 2:
If I have my textview with two static UILabels on both sides, that can be a workaround. However, this time the UITextField won't push UILabels to sides as user starts to type in. The TextField center textAligned. If I give it a constant width while creating it (programatically with CGRectMake) , it won't stretch its width as user types in. Thus, I gave it the width of view. Is there a way to auto-stretch the TextField's width as user types in that pushes the UILabels on the sides?
"Hello" [textfield] "..."
uilabel uilabel

class SpecialTextField: UITextField {
// MARK: - UITextField Observing
override internal func willMoveToSuperview(newSuperview: UIView!) {
if newSuperview != nil {
text = "Hello..."
addTarget(self, action: #selector(SpecialTextField.didChangeText), forControlEvents: .EditingChanged)
}
}
override internal func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
return false
}
private var newVal: String = "Hello..."
func didChangeText() {
var userDidEditDefaultValue = true
if (text?.characters.count > 7) { // Count of "Hello..."
if text?.rangeOfString("Hello") != nil {
if text?.rangeOfString("...") != nil {
userDidEditDefaultValue = false
}
}
}
if userDidEditDefaultValue {
text = newVal
}
newVal = text ?? "Hello..."
}
}
This will not allow user to change default value of "Hello..." OR "Hello userEntry..."
You can use delegate method to insert text in the middle.
Hope it helped.

Related

How to add text bubble styles when I separate the email address by comma as show in the screen shot attached

Hi I'm new to iOS app development. I am implemented an UITextview to add multiple address separated by comma I need to apply a style bubble when user separates the email by pressing comma or space or done button (in the keyboard.) reference screen shot from android
I am executing an email array same as below
func executeEmailArray(){
self.emailString = self.emailTF.text ?? ""
self.emailArray = emailString.components(separatedBy: ",")
print("emailArray \(self.emailArray)")
}
I formatted the uiTextView as below by using an extension
extension NewShoppingListVC: UITextViewDelegate {
func textViewDidChangeSelection(_ textView: UITextView) {
// Moves cursor to start when tapped on textView with placeholder
if emailTF.text == placeholder {
emailTF.selectedRange = start
}
}
func textViewDidChange(_ textView: UITextView) {
// Manages state of text when changed
if emailTF.text.isEmpty {
emailTF.text = placeholder
emailTF.textColor = .lightGray
} else if emailTF.text != placeholder {
emailTF.textColor = .black
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Called when you're trying to enter a character (to replace the placeholder)
if emailTF.text == placeholder {
emailTF.text = ""
}
return true
}
}
Please add some codes to explain me how to apply the textbubbles as in the image

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
}

Cursor at the start of UITextField

A ViewController consist of two TextFields named textName & textEmail. View Controller loads with cursor on textName. textName contain pre populated word "#gmail.com".
On hitting keyboard's return Key from textName, focus is moved to Textfield textEmail. Here by default, cursor is placed after the word "#gmail.com"
I would like to get the cursor placed at the start. i.e. before #gmail.com
Here is my code. When i hit return key from textName, cursor goes to the beginning of textEmail. But when I tap on textEmail directly, cursor appears after the pre populated word. Please help me!
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == self.textName{
textEmail.becomeFirstResponder()
let desiredPosition = textEmail.beginningOfDocument
textEmail.selectedTextRange = textEmail.textRangeFromPosition(desiredPosition, toPosition: desiredPosition)
}
if textField == self.textEmail{
dismissViewControllerAnimated(true, completion: nil)
}
return true
}
As a note, I did try editing did begin action for textEmail and added below code but it didn't work either.
let desiredPosition = textEmail.beginningOfDocument
textEmail.selectedTextRange = textEmail.textRangeFromPosition(desiredPosition, toPosition: desiredPosition)
Try this instead:
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == self.textName{
let beginning = textField.beginningOfDocument
textField.selectedTextRange = textField.textRange(from: beginning, to: beginning)
}
}
So remove textEmail.becomeFirstResponder() and use textField.textRange instead of textEmail.textRangeFromPosition.
And inside of the textFieldDidBeginEditing function use the parameter textField as shown in my example above.
First tou set Delegate UITextFieldDelegate
After you TextField delegate set Self in viewDidLoad
Example
textName.delegate = self
textEmail.delegate = self
then Copy this method in your viewController
func textFieldShouldReturn(textField: UITextField) -> Bool
{
if textField == textName
{
textName.resignFirstResponder()
textEmail.becomeFirstResponder()
textEmail.text = "#gmail.com"
let newPosition = textField.beginningOfDocument
textEmail.selectedTextRange = textEmail.textRangeFromPosition(newPosition, toPosition: newPosition)
}
else if textField == textEmail
{
textEmail.resignFirstResponder()
}
return true
}

UITextField with user text + static mark

I have an UITextField which user sets its luggage weight as numbers in TextField. I want to set that textfields value with weight mark (for ex 10 KG which comes from user settings) so whatever user types, there will be KG mark at the end of its textfield. Is there any way for it?
do like
initially clear the value when begin start
func textFieldShouldBeginEditing(textField: UITextField) {
textField.text = ""
}
when editing is over append the kg
func textFieldDidEndEditing(textField: UITextField) {
yourTextfieldName.text = "\(textField.text!) KG"
}
Choice-2
func textFieldDidEndEditing(textField: UITextField)
{
if !textField.text!.rangeOfString("KG").location != NSNotFound {
self.textField.text = textField.text!.stringByAppendingString("KG")
}
}
You could place a "Label" next to the UITextField.
And then just change the text of the Label to whatever the user selects.
OR (but i dont know if that works), try to get the text form the textfield, add the unit (as a string) to the string from the textfield.

Change 'Return' button function to 'Done' in swift in UITextView

I would like to get rid of the "return" function of the keyboard while the user is typing, so there are no new lines, so instead I would like the 'return' key to function as 'Done' so it would hide the keyboard.
I am using a UITextView, that is editable, so the user is able to type their post, and post it to the main timeline, but since I have fixed cells, I don't want the user to be able to press 'return' and their post would be out of range of the timeline.
I found this that works with UITextField, but not with UITextView:
func textFieldShouldReturn(textField: UITextField!) -> Bool {
textField.resignFirstResponder() //if desired
return true
}
So I just wanted to know if there is a way to do that in a UITextView, or at least to be able to hide the keyboard if pressed return, instead of creating a new line.
You can set the return key type of the text field:
textField.returnKeyType = UIReturnKeyType.done
Update
You can definitely use the same approach to set the return key to "Done", as mentioned above. However, UITextView doesn't provide a callback when user hits the return key. As a workaround, you can try to handle the textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) delegate call, and dismiss the keyboard when you detect the input of a new line character:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if (text == "\n") {
textView.resignFirstResponder()
}
return true
}
I have tried many codes and finally this worked for me in Swift 3.0 Latest [April 2019] this achieved using UITextFields
The "ViewController" class should be inherited the "UITextFieldDelegate" for making this code working.
class ViewController: UIViewController,UITextFieldDelegate
Add the Text field with the Proper Tag number and this tag number is used to take the control to appropriate text field based on incremental tag number assigned to it.
override func viewDidLoad() {
userNameTextField.delegate = self
userNameTextField.tag = 0
userNameTextField.returnKeyType = .next
passwordTextField.delegate = self
passwordTextField.tag = 1
passwordTextField.returnKeyType = .go
}
In the above code, the "returnKeyType = UIReturnKeyType.next" where will make the Key pad return key to display as "Next" you also have other options as "Join/Go" etc, based on your application change the values.
This "textFieldShouldReturn" is a method of UITextFieldDelegate controlled and here we have next field selection based on the Tag value incrementation.
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
return true;
}
return false
}
If you're working with a storyboard or xib, you can change the UITextView's Return button to 'Done' (or various other options) within Interface Builder, without the need for any setup code. Just look for this option in the Attributes inspector:
From there, you just pair it up with the UITextViewDelegate code that others have already provided here.
Swift v5:
extension ExampleViewController: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if (text == "\n") {
textView.resignFirstResponder()
}
return true
}
}
And then, in your viewDidLoad() method:
exampleTextView.delegate = self
Working in Swift 4
Add this in viewDidLoad().
textField.returnKeyType = UIReturnKeyType.Done
Add this anywhere you like.
extension UITextView: UITextViewDelegate {
public func textViewDidChange(_ textView: UITextView) {
if text.last == "\n" { //Check if last char is newline
text.removeLast() //Remove newline
textView.resignFirstResponder() //Dismiss keyboard
}
}
}

Resources