Disable UIButton after UITextField is no longer hidden? - ios

I have a simple task but I don't seem to be able to figure it out. I have a UIViewController that has 5 UITextFields. 2 of those UITextFields are always visible. The other 3 are being shown when the user hits a UIButton. My goal is to disable the UIButton so it's obvious to the user that they cannot "add" more UITextFields after ALL of the UITextFields are visible. I tried to do this:
#IBAction func addTextFieldPressed(_ sender: UIButton) {
if !thirdChoiceTextField.isHidden, !forthChoiceTextField.isHidden, !fifthChoiceTextField.isHidden {
addTextFieldButton.isEnabled = false
}
if thirdChoiceTextField.isHidden {
UIView.animate(withDuration: 0.2) {
self.thirdChoiceTextField.isHidden = false
}
}
else if forthChoiceTextField.isHidden {
UIView.animate(withDuration: 0.2) {
self.forthChoiceTextField.isHidden = false
}
}
else {
UIView.animate(withDuration: 0.2) {
self.fifthChoiceTextField.isHidden = false
}
}
}
But it doesn't work. You're able to add the UITextFields. There's also a UIButton that allows the user to remove the 3 added UITextField. So, I have to make sure that if all of the text fields are shown, the UIButton responsible for adding more UITextFields would be disabled, but if any of the UITextFields is removed (.isHidden = true), the button should be enabled once again.
UPDATE: This is the code that runs after the user hits the "hide" button and it basically hides either 3rd, 4th or 5th UITextField
#objc func hideTextField(_ sender: UIButton) {
if let field = sender.superview?.superview as? UITextField, !field.isHidden {
UIView.animate(withDuration: 0.2) {
field.text = ""
field.isHidden = true
}
}
}

There is a missing else condition.
#IBAction func addTextFieldPressed(_ sender: UIButton) {
if !thirdChoiceTextField.isHidden, !forthChoiceTextField.isHidden, !fifthChoiceTextField.isHidden {
addTextFieldButton.isEnabled = false
}
else{
addTextFieldButton.isEnabled = true
}
if thirdChoiceTextField.isHidden {
UIView.animate(withDuration: 0.2) {
self.thirdChoiceTextField.isHidden = false
}
}
else if forthChoiceTextField.isHidden {
UIView.animate(withDuration: 0.2) {
self.forthChoiceTextField.isHidden = false
}
}
else {
UIView.animate(withDuration: 0.2) {
self.fifthChoiceTextField.isHidden = false
}
}
}
Update (try adding this to enable the button)
#objc func hideTextField(_ sender: UIButton) {
if let field = sender.superview?.superview as? UITextField, !field.isHidden {
UIView.animate(withDuration: 0.2) {
field.text = ""
field.isHidden = true
}
}
if !thirdChoiceTextField.isHidden, !forthChoiceTextField.isHidden, !fifthChoiceTextField.isHidden {
addTextFieldButton.isEnabled = false
}
else{
addTextFieldButton.isEnabled = true
}
}

Related

how to hide/view header view table in iOS swift

I have static UItableview to hold user form. I added header view in the table to show email validation files my problem is the header does not show a smooth transition between hiding/show and overlap with the first row
I want to ask how I can fix the hight of the table header view and does not make it overlap
code
#IBOutlet weak var errorView: UIView!
#IBAction func next(_ sender: Any) {
let newUserEmail = self.txtfEmail.text
if isValidEmail(newUserEmail!) {
performSegue(withIdentifier: "addInventryToNewUser", sender: self)
}
else {
cellemail.layer.borderWidth = 2.0
cellemail.layer.borderColor = UIColor.red.cgColor
let f = errorView.frame;
errorView.frame = CGRect(x: f.origin.x, y: f.origin.y, width: f.width, height: 21);
errorView.isHidden = false
lblError.text = "❌ Invalid email address."
}
}
You need to apply some animation for a smooth transition. Here's how:
#IBAction func next(_ sender: Any) {
let newUserEmail = self.txtfEmail.text
if isValidEmail(newUserEmail!) {
performSegue(withIdentifier: "addInventryToNewUser", sender: self)
}
else {
cellemail.layer.borderWidth = 2.0
cellemail.layer.borderColor = UIColor.red.cgColor
UIView.animate(withDuration: 0.5) {
self.errorView.frame.size.height = 21
}
errorView.isHidden = false
lblError.text = "❌ Invalid email address."
}
}
I have no enough reputation to add a comment, but the answer on "how to hide it after 5 seconds?" Is:
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// your code to hide view here
}
I will combine the two answer:
#IBAction func next(_ sender: Any) {
let newUserEmail = self.txtfEmail.text
if isValidEmail(newUserEmail!) {
performSegue(withIdentifier: "addInventryToNewUser", sender: self)
}
else {
cellemail.layer.borderWidth = 2.0
cellemail.layer.borderColor = UIColor.red.cgColor
UIView.animate(withDuration: 0.5) {
self.errorView.frame.size.height = 21
}
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// your code to hide view here
}
errorView.isHidden = false
lblError.text = "❌ Invalid email address."
}
}

How do you really hide and show a tab bar when tapping on part of your view? (no buttons but any location of the screen)

override func viewDidLoad() {
let tap = UITapGestureRecognizer(target: self, action: #selector(touchHandled))
view.addGestureRecognizer(tap)
}
#objc func touchHandled() {
tabBarController?.hideTabBarAnimated(hide: true)
}
extension UITabBarController {
func hideTabBarAnimated(hide:Bool) {
UIView.animate(withDuration: 2, animations: {
if hide {
self.tabBar.transform = CGAffineTransform(translationX: 0, y: 100)
} else {
self.tabBar.transform = CGAffineTransform(translationX: 0, y: -100)
}
})
}
}
I can only hide the tab bar but I can't make it show when you tap again. I tried to look for answers on stack overflow but the answers seems to only work if you're using a button or a storyboard.
Have a variable isTabBarHidden in class which stores if the tabBar has been animated to hide. (You could have used tabBar.isHidden, but that would complicate the logic a little bit when animate hiding and showing)
class ViewController {
var isTabBarHidden = false // set the default value as required
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(touchHandled))
view.addGestureRecognizer(tap)
}
#objc func touchHandled() {
guard let tabBarControllerFound = tabBarController else {
return
}
tabBarController?.hideTabBarAnimated(hide: !isTabBarHidden)
isTabBarHidden = !isTabBarHidden
}
}
Generalised solution with protocol which will work in all the screens
Create UIViewController named BaseViewController and make it base class of all of your view controllers
Now Define protocol
protocol ProtocolHideTabbar:class {
func hideTabbar ()
}
protocol ProtocolShowTabbar:class {
func showTabbar ()
}
extension ProtocolHideTabbar where Self : UIViewController {
func hideTabbar () {
self.tabBarController?.tabBar.isHidden = true
}
}
extension ProtocolShowTabbar where Self : UIViewController {
func showTabbar () {
self.tabBarController?.tabBar.isHidden = false
}
}
By default we want show tabbar in every view controller so
extension UIViewController : ProtocolShowTabbar {}
In your BaseView Controller
in view will appear method add following code to show hide based on protocol
if self is ProtocolHideTabbar {
( self as! ProtocolHideTabbar).hideTabbar()
} else if self is ProtocolShowTabbar{
( self as ProtocolShowTabbar).showTabbar()
}
How to use
Simply
class YourViewControllerWithTabBarHidden:BaseViewController,ProtocolHideTabbar {
}
Hope it is helpful
Tested 100% working
Please try below code for that in UITabBarController subclass
var isTabBarHidden:Bool = false
func setTabBarHidden(_ tabBarHidden: Bool, animated: Bool,completion:((Void) -> Void)? = nil) {
if tabBarHidden == isTabBarHidden {
self.view.setNeedsDisplay()
self.view.layoutIfNeeded()
//check tab bar is visible and view and window height is same then it should be 49 + window Heigth
if (tabBarHidden == true && UIScreen.main.bounds.height == self.view.frame.height) {
let offset = self.tabBar.frame.size.height
self.view.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:self.view.frame.height + offset)
}
if let block = completion {
block()
}
return
}
let offset: CGFloat? = tabBarHidden ? self.tabBar.frame.size.height : -self.tabBar.frame.size.height
UIView.animate(withDuration: animated ? 0.250 : 0.0, delay: 0.1, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: [.curveEaseIn, .layoutSubviews], animations: {() -> Void in
self.tabBar.center = CGPoint(x: CGFloat(self.tabBar.center.x), y: CGFloat(self.tabBar.center.y + offset!))
//Check if View is already at bottom so we don't want to move view more up (it will show black screen on bottom ) Scnario : When present mail app
if (Int(offset!) <= 0 && UIScreen.main.bounds.height == self.view.frame.height) == false {
self.view.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:self.view.frame.height + offset!)
}
self.view.setNeedsDisplay()
self.view.layoutIfNeeded()
}, completion: { _ in
if let block = completion {
block()
}
})
isTabBarHidden = tabBarHidden
}
Hope it is helpful

Unable to set progress bar progress twice in iOS?

I have UIProgressView.On begin to text edit for a UITextField I set the value of progress bar to 1 . Before that initially I make it progress to 0.1 .But it is setting progress only once. If I first set progress to 0.1 then after it does not set progress to 1.please tell me what is the issue ?
func textFieldDidBeginEditing(_ textField: UITextField) {
setViewBottomColor()
var view:BottomView?
if textField == textFieldEmail {
view = self.bottomViewFirst
view?.trackTintColor = Constant.AppColor.viewBottom
view?.progressTintColor = Constant.AppColor.purpleViewColor
}
else if textField == textFieldPassword {
view = self.bottomViewSecond
view?.trackTintColor = Constant.AppColor.viewBottom
view?.progressTintColor = Constant.AppColor.purpleViewColor
}
if view != nil {
view?.setProgress(1, animated: true)
UIView.animate(withDuration: 1.0, animations: {
view?.layoutIfNeeded()
}, completion: { (finish) in
})
}
}
func setViewBottomColor() {
self.bottomViewFirst.trackTintColor = Constant.AppColor.viewBottom
self.bottomViewFirst.progressTintColor = Constant.AppColor.purpleViewColor
self.bottomViewFirst?.setProgress(0.1, animated: false)
self.bottomViewFirst?.layoutIfNeeded()
}
Check below code snippet I have used to check. It is working fine.
You may check few things:
All IBOutlets connections must be there.
If you are using custom UIProgressView as BottomView then you must changed both progress view class in xib/storyboard as well.
No Need to have view animation if for progress value change only.
func textFieldDidBeginEditing(_ textField: UITextField) {
resetProgresses()
var view = UIProgressView()
if textField == t1 {
view = self.progressBar
view.trackTintColor = .red
view.progressTintColor = .green
}
else if textField == t2 {
view = self.progressBar2
view.trackTintColor = .green //Constant.AppColor.viewBottom
view.progressTintColor = .red//Constant.AppColor.purpleViewColor
}
if view != nil {
view.setProgress(1, animated: true)
}
}
func resetProgresses() {
self.progressBar?.setProgress(0.1, animated: true)
self.progressBar2?.setProgress(0.1, animated: true)
}

How to toggle a UITextField secure text entry (hide password) in Swift?

I currently have a UITextfield with an eye icon in it that when pressed is supposed to toggle the secure text entry on and off.
I know you can check mark the "secure text entry" box in the attributes inspector but how to do it so it toggles whenever the icon is pressed?
Use this code,
iconClick is bool variable, or you need other condition check it,
var iconClick = true
eye Action method:
#IBAction func iconAction(sender: AnyObject) {
if iconClick {
passwordTF.secureTextEntry = false
} else {
passwordTF.secureTextEntry = true
}
iconClick = !iconClick
}
hope its helpful
An unintended side-effect of this is that if the user toggles to insecure, and then back to secure, the existing text will be cleared if the user continues typing. The cursor may also end up in the wrong position unless we reset the selected text range.
Below is an implementation that handles these cases (Swift 4)
extension UITextField {
func togglePasswordVisibility() {
isSecureTextEntry = !isSecureTextEntry
if let existingText = text, isSecureTextEntry {
/* When toggling to secure text, all text will be purged if the user
continues typing unless we intervene. This is prevented by first
deleting the existing text and then recovering the original text. */
deleteBackward()
if let textRange = textRange(from: beginningOfDocument, to: endOfDocument) {
replace(textRange, withText: existingText)
}
}
/* Reset the selected text range since the cursor can end up in the wrong
position after a toggle because the text might vary in width */
if let existingSelectedTextRange = selectedTextRange {
selectedTextRange = nil
selectedTextRange = existingSelectedTextRange
}
}
}
This snippet is using the replace(_:withText:) function because it triggers the .editingChanged event, which happens to be useful in my application. Just setting text = existingText should be fine as well.
Why to use an extra var. In the action method of the eye button just do as below
password.secureTextEntry = !password.secureTextEntry
UPDATE
Swift 4.2 (as per #ROC comment)
password.isSecureTextEntry.toggle()
I wrote extension for the same. To provide Password toggle.
In your Assets first add images that you want for toggle.
Add following extension for UITextField.
extension UITextField {
fileprivate func setPasswordToggleImage(_ button: UIButton) {
if(isSecureTextEntry){
button.setImage(UIImage(named: "ic_password_visible"), for: .normal)
}else{
button.setImage(UIImage(named: "ic_password_invisible"), for: .normal)
}
}
func enablePasswordToggle(){
let button = UIButton(type: .custom)
setPasswordToggleImage(button)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -16, bottom: 0, right: 0)
button.frame = CGRect(x: CGFloat(self.frame.size.width - 25), y: CGFloat(5), width: CGFloat(25), height: CGFloat(25))
button.addTarget(self, action: #selector(self.togglePasswordView), for: .touchUpInside)
self.rightView = button
self.rightViewMode = .always
}
#IBAction func togglePasswordView(_ sender: Any) {
self.isSecureTextEntry = !self.isSecureTextEntry
setPasswordToggleImage(sender as! UIButton)
}
}
Call extension on your UITextField Outlet
override func viewDidLoad() {
super.viewDidLoad()
txtPassword.enablePasswordToggle()
txtConfirmPassword.enablePasswordToggle()
}
Swift 4 solution
You don't need extra if statement for simple toggle isSecureTextEntry property
func togglePasswordVisibility() {
password.isSecureTextEntry = !password.isSecureTextEntry
}
But there is a problem when you toggle isSecureTextEntry UITextField doesn't recalculate text width and we have extra space to the right of the text. To avoid this you should replace text this way
func togglePasswordVisibility() {
password.isSecureTextEntry = !password.isSecureTextEntry
if let textRange = password.textRange(from: password.beginningOfDocument, to: password.endOfDocument) {
password.replace(textRange, withText: password.text!)
}
}
UPDATE
Swift 4.2
Instead of
password.isSecureTextEntry = !password.isSecureTextEntry
you can do this
password.isSecureTextEntry.toggle()
Use UITextFiled rightView to show toggle button
var rightButton = UIButton(type: .custom)
rightButton.frame = CGRect(x:0, y:0, width:30, height:30)
yourtextfield.rightViewMode = .always
yourtextfield.rightView = rightButton
If you need TextField with similar feature in multiple places its best to subclass the UITextField like follwing example -
import UIKit
class UIShowHideTextField: UITextField {
let rightButton = UIButton(type: .custom)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
required override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
rightButton.setImage(UIImage(named: "password_show") , for: .normal)
rightButton.addTarget(self, action: #selector(toggleShowHide), for: .touchUpInside)
rightButton.frame = CGRect(x:0, y:0, width:30, height:30)
rightViewMode = .always
rightView = rightButton
isSecureTextEntry = true
}
#objc
func toggleShowHide(button: UIButton) {
toggle()
}
func toggle() {
isSecureTextEntry = !isSecureTextEntry
if isSecureTextEntry {
rightButton.setImage(UIImage(named: "password_show") , for: .normal)
} else {
rightButton.setImage(UIImage(named: "password_hide") , for: .normal)
}
}
}
After which you can use it in any ViewController,
class ViewController: UIViewController {
#IBOutlet var textField: UIShowHideTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.becomeFirstResponder()
}
}
For Objective c
set image for RightButton In viewdidload Method
[RightButton setImage:[UIImage imageNamed:#"iconEyesOpen"] forState:UIControlStateNormal];
[RightButton setImage:[UIImage imageNamed:#"iconEyesClose"] forState:UIControlStateSelected];
and then set action method for that RightButton
-(IBAction)RightButton:(id)sender
{
if (_rightButton.selected)
{
_rightButton.selected = NO;
_passwordText.secureTextEntry = YES;
if (_passwordText.isFirstResponder) {
[_passwordText resignFirstResponder];
[_passwordText becomeFirstResponder];
}
}
else
{
_rightButton.selected = YES;
_passwordText.secureTextEntry = NO;
if (_passwordText.isFirstResponder) {
[_passwordText resignFirstResponder];
[_passwordText becomeFirstResponder];
}
}
}
Swift 3
// MARK: Btn EyeAction
#IBAction func btnEyeAction(_ sender: Any) {
if(iconClick == true) {
txtPassword.isSecureTextEntry = false
iconClick = false
} else {
txtPassword.isSecureTextEntry = true
iconClick = true
}
}
Shortest!
I think this is the shortest solution for secure entry as well as updating the picture of the button.
#IBAction func toggleSecureEntry(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
textfieldPassword.isSecureTextEntry = !sender.isSelected
}
Assign the show/hide picture of the button according to the state selected /default , no need to create any variable or outlet.
This worked for me on Swift 5.0
#IBAction func changePasswordVisibility(_ sender: UIButton) {
passwordField.isSecureTextEntry.toggle()
if passwordField.isSecureTextEntry {
if let image = UIImage(systemName: "eye.fill") {
sender.setImage(image, for: .normal)
}
} else {
if let image = UIImage(systemName: "eye.slash.fill") {
sender.setImage(image, for: .normal)
}
}
}
Button attributes:
Result:
Swift 3
passwordTF.isSecureTextEntry = true
passwordTF.isSecureTextEntry = false
#IBAction func eye_toggle_clicked(sender: AnyObject)
{
if toggleBtn.tag == 0
{
passwordTxt.secureTextEntry=true
toggleBtn.tag=1
}
else
{
passwordTxt.secureTextEntry=false
toggleBtn.tag=0
}
}
As others have noted, the property is secureTextEntry, but you won't find this in the UITextField documentation, as it is actually inherited by a UITextField through the UITextInputTraits protocol- https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/#//apple_ref/occ/intfp/UITextInputTraits/secureTextEntry
You can simply toggle this value each time your button is tapped:
#IBAction func togglePasswordSecurity(sender: UIButton) {
self.passwordField.secureTextEntry = !self.passwordField.secureTextEntry
}
try this line:
#IBAction func btnClick(sender: AnyObject) {
let btn : UIButton = sender as! UIButton
if btn.tag == 0{
btn.tag = 1
textFieldSecure.secureTextEntry = NO
}
else{
btn.tag = 0
textFieldSecure.secureTextEntry = NO;
}
}
Here is your answer no need to take any bool var:
#IBAction func showHideAction(sender: AnyObject) {
if tfPassword.secureTextEntry{
tfPassword.secureTextEntry = false
}else{
tfPassword.secureTextEntry = true;
}
}
First you need to set image(visible or hide) of button of eye for different state (selected or normal)
than connect IBAction and write code like
#IBAction func btnPasswordVisiblityClicked(_ sender: Any) {
(sender as! UIButton).isSelected = !(sender as! UIButton).isSelected
if (sender as! UIButton).isSelected {
txtfPassword.isSecureTextEntry = false
} else {
txtfPassword.isSecureTextEntry = true
}
}
In Swift 4
var iconClick : Bool!
override func viewDidLoad() {
super.viewDidLoad()
iconClick = true
}
#IBAction func showHideAction(_ sender: Any)
{
let userPassword = userPasswordTextFiled.text!;
if(iconClick == true) {
userPasswordTextFiled.isSecureTextEntry = false
iconClick = false
} else {
userPasswordTextFiled.isSecureTextEntry = true
iconClick = true
}
}
Assignment values change from YES/NO to true/false boolean values.
password.secureTextEntry = true //Visible
password.secureTextEntry = false //InVisible
You can try this code..
i think it's helpful.
Use button with eye image
and make buttonHandler method
set Tag for button with value 1
-(IBAction) buttonHandlerSecureText:(UIButton *)sender{
if(sender.tag ==1){
[self.textField setSecureTextEntry:NO];
sender.tag = 2;
}
else{
[self.textField setSecureTextEntry:YES];
sender.tag = 1;
}
}
For Xamarin folks:
passwordField.SecureTextEntry = passwordField.SecureTextEntry ? passwordField.SecureTextEntry = false : passwordField.SecureTextEntry = true;
Try this code in swift 4, tried to make a reusable code within a controller. I have set different image for buttons in storyboard as shown in the link https://stackoverflow.com/a/47669422/8334818
#IBAction func clickedShowPassword(_ sender: UIButton) {
var textField :UITextField? = nil
print("btn ",sender.isSelected.description)
switch sender {
case encryptOldPswdBtn:
encryptOldPswdBtn.isSelected = !encryptOldPswdBtn.isSelected
textField = oldPasswordTextField
default:
break
}
print("text ",textField?.isSecureTextEntry.description)
textField?.isSecureTextEntry = !(textField?.isSecureTextEntry ?? false)
}
#objc func togglePasscode(){
switch textfield.isSecureTextEntry{
case true:
textfield.isSecureTextEntry = false
case false:
textfield.isSecureTextEntry = true
}
}
Here is a easy and more readable solution using Switch statement.
Hope this is simpler solution rather than creating a BOOL object globally.
#IBAction func passwordToggleButton(sender: UIButton) {
let isSecureTextEntry = passwordTextField.isSecureTextEntry
passwordTextField.isSecureTextEntry = isSecureTextEntry ? false : true
if isSecureTextEntry {
visibilityButton.setImage(UIImage(named: "visibility"), for: .normal)
} else {
visibilityButton.setImage(UIImage(named: "visibility_off"), for: .normal)
}
}
only add this line into your code replace you TextField name with "textfield" Done:
you need to change the isSecureTextEntry propertity to change true for password type textFiled like ......
textField.isSecureTextEntry = true
sender.isSelected = !sender.isSelected
if(sender.isSelected == true) {
RegPasswordField.isSecureTextEntry = false
sender.setBackgroundImage(UIImage(systemName: "eye.fill"), for: .normal)
} else {
RegPasswordField.isSecureTextEntry = true
sender.setBackgroundImage(UIImage(systemName: "eye"), for: .normal)
}
Swift 5 Please use this
var btnClick = true
if(btnClick == true) {
passwordTextField.isSecureTextEntry = false
} else {
passwordTextField.isSecureTextEntry = true
}
btnClick = !btnClick
}
var viewingPassword = true
#IBAction func btnEyeAction(_ sender: Any) {
passwordTF.isSecureTextEntry = viewingPassword ? false : true
viewingPassword.toggle()
}

UITextField: When beginning input, textfield bounces up, and then bounces down

I've seen this with UITextView too. Clearly, I'm missing something pretty basic.
I've tried:
- Setting textsize to small
- UITextField: Setting 1 line, no resize
- Removing the ability to move the texfield
import UIKit
class XViewController: UIViewController, UITextFieldDelegate, UIGestureRecognizerDelegate {
// UI elements
let cancelButton = UIButton()
let okButton = UIButton()
var image:UIImage?
var previewImageView:UIImageView = UIImageView()
let textField = UITextField()
let tapGestureRecognizer = UITapGestureRecognizer()
let textFieldTypingPositionY:CGFloat = 200
var textFieldActualPositionY:CGFloat!
let textFieldHeight:CGFloat = 40
var draggingTextField:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupTextField()
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString text: String) -> Bool {
let textFieldSize = textField.text!.characters.count
let textSize = text.characters.count
if text == "\n" && textFieldSize == 0 {
// press return on empty textfield
textField.text = ""
hideTextField()
return true
} else if textFieldSize == 1 && text == "" {
// backspace to empty
textField.text = ""
hideTextField()
return true
} else if text == "\n" {
textField.resignFirstResponder()
} else if (textFieldSize + textSize) > 30 {
let diff = (textFieldSize - textSize) - 30
textField.text = (text as NSString).substringToIndex(diff - 1)
}
return true
}
func setupTextField() {
// TextView
textField.translatesAutoresizingMaskIntoConstraints = false
textField.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.7)
textField.textColor = UIColor.whiteColor()
textField.font = UIFont.systemFontOfSize(14.0)
textField.textAlignment = NSTextAlignment.Center
textField.text = ""
textField.hidden = true
textField.delegate = self
self.view.addSubview(textField);
// Text view constraints
let leftConstraint = textField.leftAnchor.constraintEqualToAnchor(view.leftAnchor)
let rightConstraint = textField.rightAnchor.constraintEqualToAnchor(view.rightAnchor)
let heightConstraint = textField.heightAnchor.constraintEqualToConstant(textFieldHeight)
let verticalConstraint = textField.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 200)
NSLayoutConstraint.activateConstraints([leftConstraint, rightConstraint, heightConstraint, verticalConstraint])
// Tap gesture recognizer; if no text view is visible, shows text view at vertical location of tap
tapGestureRecognizer.delegate = self
tapGestureRecognizer.addTarget(self, action: "tapGesture:")
view.addGestureRecognizer(tapGestureRecognizer)
}
func tapGesture(rec:UITapGestureRecognizer) {
// Show the textView in a location?
if textField.hidden == false {
if (textField.text!.characters.count == 0) {
hideTextField()
} else {
restoreTextFieldPosition()
}
} else {
moveTextFieldToEditingPosition()
}
}
func moveTextFieldToEditingPosition() {
// Textview animates into position a la snapchat
self.textField.userInteractionEnabled = false
textField.hidden = false
UIView.animateWithDuration(0.2, animations: { () -> Void in
self.textField.center.y = self.textFieldTypingPositionY
}, completion: { (Bool) -> Void in
self.textField.userInteractionEnabled = true
self.textField.becomeFirstResponder()
})
}
func hideTextField() {
// Hide text view and reset position
textField.resignFirstResponder()
textField.userInteractionEnabled = false
UIView.animateWithDuration(0.2, animations: { () -> Void in
}, completion: { (Bool) -> Void in
self.textField.hidden = true
})
}
func restoreTextFieldPosition() {
// Restore original position of textview after exiting keyboard
self.textField.userInteractionEnabled = false
textField.resignFirstResponder()
UIView.animateWithDuration(0.2, animations: { () -> Void in
}, completion: { (Bool) -> Void in
self.textField.userInteractionEnabled = true
})
}
}
I had this issue with iOS 9. It was ok on iOS 7 and 8. Basically I have a UITextField in a collection view cell. Sometimes when the user is done typing and editing ends, the text "bounces" up then down again into its correct position. Very strange and annoying glitch. Simply making this tweak fixed the issue on iOS 9 and proved to be safe on iOS 7 and 8:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[textField layoutIfNeeded]; //Fixes iOS 9 text bounce glitch
//...other stuff
}
this is strange behaviour of textField. I have same issue and the reason is what you are changing the position of textField.
Solution
whatever you have write code for changing position (Y position in your case) using uiview.animation.... Remove this code
And i'm damn sure this bounce will occur when you remove the focus or switch to another control.
Finally, Remove animation code or leave this bounce animation (not bad).
:)
Not sure if you solved this, but for me it was because I had a piece of code in my UITextFieldDelegate calling layoutIfNeeded - which was causing all the auto-layout constraints to be recalculated.
I removed the layoutIfNeeded and seemed to have fixed the bouncing

Resources