UITextfield text position not animating while widt

2019-03-31 13:38发布

问题:

I have three UITextField aligned in a container used to choose a date.

At first only the month textfield is shown in the container and takes the full width, then when the user chose the month, the day textfield appear and they both take half of the container.

The text alignement in these textfields is centered.

My problem is that when I animate their size, the text doesn't animate and jumps directly to the final position while the width of the textfields animate correctly.

Step 1 : The TextField Before Animation

Step 2 : The TexField width is animating but the text is already in the final position

Step 3 : The TexField Finished Animating

My code used to animate the constraint :

monthTextfieldTrailingConstraint.priority = currentDateSelectionType == .month ? UILayoutPriorityDefaultHigh : UILayoutPriorityDefaultLow
dayTextfieldTrailingConstraint.priority = currentDateSelectionType == .day ? UILayoutPriorityDefaultHigh : UILayoutPriorityDefaultLow
yearTextfieldTrailingConstraint.priority = currentDateSelectionType == .year ? UILayoutPriorityDefaultHigh : UILayoutPriorityDefaultLow

UIView.animate(withDuration: nextStepAnimationDuration) {
    self.layoutIfNeeded()
}

回答1:

I had almost the exact same question. Please see my question and its answer for reference: UITextField text jumps when animating width constraint

Solution Demo

The solution is to embed your textfields within another view (e.g. another UITextField or a UIView). In the gif below, I put a textfield within a textfield. Note that helloWorldTextField has a blue border to show its location within the second textfield behind it.

Instructions

  1. For each field (month, day), make two textfields, e.g. monthTextField and monthBorderTextField.
  2. Remove monthTextField's border and background color. Keep borderTextField's border and background color.
  3. Center monthTextField within borderTextField.
  4. Animate the width of borderTextField as needed.

Github link and Code

Here is the link to my project on Github: https://github.com/starkindustries/ConstraintAnimationTest

Here is the code for my test project for my MyViewController class. Everything else is setup in the storyboard which can be viewed on Github at the link above.

class MyViewController: UIViewController {

    // Hello World TextField Border var
    @IBOutlet weak var borderTextFieldWidth: NSLayoutConstraint!

    // Button Vars
    @IBOutlet weak var myButton: UIButton!
    var grow: Bool = false

    func animateGrowShrinkTextFields(grow: Bool, duration: TimeInterval) {
        if grow {
            UIView.animate(withDuration: duration, animations: {
                self.borderTextFieldWidth.constant = 330
                self.view.layoutIfNeeded()
            }, completion: { (finished: Bool) in
                print("Grow animation complete!")
            })
        } else {
            UIView.animate(withDuration: duration, animations: {
                self.borderTextFieldWidth.constant = 115
                self.view.layoutIfNeeded()
            }, completion: { (finished: Bool) in
                print("Shrink animation complete!")
            })
        }
    }

    @IBAction func toggle(){
        let duration: TimeInterval = 1.0
        grow = !grow
        let title = grow ? "Shrink" : "Grow"
        myButton.setTitle(title, for: UIControlState.normal)
        animateGrowShrinkTextFields(grow: grow, duration: duration)
    }
}

Notes and References

What led me to this solution was @JimmyJames's comment: "You are just animating the UITextField width, but the content inside is not animated."

I researched how to animate font changes and came across this question: Is there a way to animate changing a UILabel's textAlignment?

In that question @CSmith mentioned that "you can animate the FRAME, not the textAlignment" https://stackoverflow.com/a/19251634/2179970

The accepted answer in that question suggests to use a UILabel within another frame. https://stackoverflow.com/a/19251735/2179970