14

When I animate the location of my UITextField subclass, the text in the field jumps out of step with the location of the UITextField holding it, which is very jarring and I can't figure out why it happens: before during during during end

My subclass adds a button to the right hand side of the text field that when tapped calls a method on the view controller, which changes the textfield border colour and moves the text field up the screen by changing the top space constraint of the text field, and a couple of other views located above it.

[UIView animateWithDuration:0.3
                     animations:^{
                         self.tableViewBottomSpaceConstraint.constant = 0;
                         self.mainLabelHeightConstraint.constant = 0;
                         self.subLabelTopSpaceConstraint.constant = 0;
                         self.postCodeFieldTopSpaceConstraint.constant = 12;
                         [self.view layoutIfNeeded];

                     }];
Jasper
  • 7,031
  • 3
  • 35
  • 43
Andrew Davis
  • 2,310
  • 1
  • 24
  • 43
  • same problem here bro....am also facing the same problem. in my custom class am just giving a padding from left to the text field. could not figured it out yet. – Mahesh Agrawal Jun 15 '15 at 12:23
  • 2
    Possible duplicate of [Text in UITextField moves up after editing (center while editing)](http://stackoverflow.com/questions/9674566/text-in-uitextfield-moves-up-after-editing-center-while-editing) – pronebird Oct 21 '15 at 14:13

3 Answers3

11

i fixed this. change your code to this. It will work.

[UIView animateWithDuration:0.3
                 animations:^{
                     self.tableViewBottomSpaceConstraint.constant = 0;
                     self.mainLabelHeightConstraint.constant = 0;
                     self.subLabelTopSpaceConstraint.constant = 0;
                     self.postCodeFieldTopSpaceConstraint.constant = 12;
                     [self.view layoutSubviews];

                 }];

or if this doesn't work then instead of

[self.view layoutSubviews];

use the parent view of the text field and layoutSubviews. In my case this worked. I think this answer is eligible for the bounty. Thanks.

EDIT:

I found the reason of this. When we are trying to layoutIfNeeded it means its changing the outer layout first and after it changes its layout its changing the inner text of UITextField because we are not forcefully changing layout of all subviews of that text field. After all UITextField is made up of UIView and Label and other base elements. But when we trying to layoutSubviews its changing layout of all subviews simultaneously. Thats why the bouncing is gone.

Mahesh Agrawal
  • 3,348
  • 20
  • 34
  • 1
    Never call -layoutSubviews directly. Instead call -layoutIfNeeded. – pronebird Oct 20 '15 at 20:32
  • I have tried layoutIfNeeded but it wasn't worked in iOS 8. I am doing this because the UITextField is made up of several UIControls out of which one is UILabel which is bouncing and if we do layoutIfNeeded i think its not changing its layout as required. Please check in iOS 8 by adding layoutIfNeeded. It won't work and thats why this question posted i think. But now in iOS 9 it may work. Am not sure about that. – Mahesh Agrawal Oct 21 '15 at 05:29
  • Usually you would call setNeedsLayout before layoutIfNeeded to tell UIKit that this particular view needs to update layout. There is a certain order and internal infrastructure that handles updates and makes sure they work properly with both old "springs and struts" and Autolayout. I do this because it works is not an explanation. You may cause more damage and inconsistency in UI if you had more complex UI layout. As per documentation, you should never call layoutSubviews manually regardless of side-effects that you see, even if that solves your problem. (most likely temporarily) – pronebird Oct 21 '15 at 14:01
  • 1
    If you are curious how to fix this issue for iOS 9: http://stackoverflow.com/a/32996503/351305. – pronebird Oct 21 '15 at 14:13
  • thanks for pointing us in right direction. really appreciate. – Mahesh Agrawal Oct 21 '15 at 14:19
2

It looks like for some reason your UI isn't in a settled state before the animation is triggered.

Try adding a call to [self.view layoutIfNeeded]; before your animation block, and use [self.view layoutIfNeeded]; at the end of your block rather than [self.view layoutSubviews]; which shouldn't really be used in this context.

2

For iOS 9 or above, this solve the issue

Objective-C:

 - (void)textFieldDidEndEditing:(UITextField *)textField
 {
    [textField layoutIfNeeded]; //Fixes iOS 9 text bounce glitch
    //...other stuff
 }

Swift:

  func textFieldDidEndEditing(_ textField: UITextField) {
    textField.layoutIfNeeded() //Fixes iOS 9 text bounce glitch
    //...other stuff
  }

Google takes me here. Under @Mahesh Agrawal 's answer, @Andy comments a link that links to Here which is the best solution I can find for this problem.

Community
  • 1
  • 1
nuynait
  • 1,912
  • 20
  • 27