Reputation: 16246
My view controller's view has a child view -a "login" panel of sorts, with two input text fields- placed at its center, with autolayout constraints set in Interface Builder. The view controller class also has an outlet set to reference the vertical constraint and manipulate it at run time.
On startup -viewDidLayoutSubviews()
-, I cache the value of the vertical constraint in a property (constraintInitialValue
), calculate a value that will hide the panel beneath the view's bounds (based on both the panel's and the view's sizes) and apply that value immediately, effectively hiding the panel before the user sees the view. I also cache this calculated "off-screen" value of the constrain in another property (constraintOffscreenValue
), for later use (e.g., to "hide" the panel).
(I do all this initial setup in viewDidLayoutSubviews()
because it is the first opportunity to get the actual bounds of my view controller's view.)
(For the record, the original constraint value is 0.0
: center Y, no offset. And, for an iPhone 6 and the current size of my panel, the "offscreen value" is -453.0.)
In the background, I authenticate the user. If that fails, I animate the login panel back into its original position (the center of the screen).
So far, so good.
Next, when the user enters their credentials and hits the return key for the password (the last input field), I perform some local validation (e.g., strings are not empty) and "dismiss" the panel by animating it back into its off-screen position. If I do it with the following code:
UIView.animateWithDuration(NSTimeInterval(0.3),
delay:NSTimeInterval(0.0),
options:UIViewAnimationOptions.CurveEaseOut,
animations: { () -> Void in
self.panelVerticalSpaceConstraint.constant = self.constraintOffscreenValue
self.view.layoutIfNeeded()
},
completion: { (finished) -> Void in
}
)
(viewDidLayoutSubviews()
gets called several times during the animation, but from the second call onwards my code just returns right away. The initial setup I mentioned above does not get executed more than once)
My panel moves slightly upwards, and then the same ammount downwards, ending at the center of the screen (instead, it should disappear at the very bottom).
If I try changing the animation duration from 0.3
to 10.0
(to get a proper look at what's happening), instead the panel quickly "jumps" to almost above the upper margin of the view, and slowly animates back into the center. That is, if the initial jump didn't happen, I would obtain the desired result (move to the bottom of the view).
Any suggestions? Thanks in advance...
ADDENDUM: If, instead of trying to animate the panel downwards, I set the constraint to its off-screen value immediately, like this:
self.panelVerticalSpaceConstraint.constant = self.constraintOffscreenValue
self.view.layoutIfNeeded()
...it immediately disappears, only to bounce back into the center of the view right away! Where did that animation come from? Is the constraint somehow "resisting change"?
Upvotes: 1
Views: 379
Reputation: 16246
OK, I found the answer. For some weird quirk of fate, I can only find my mistakes after posting a question to SO (curse me a million times!).
It turns out another, separate animation was being executed concurrently (and thus, interfering with) my lower-the-panel-to-below-the-bottom-of-the-screen animation:
I happen to have a similar animation, to adjust the panel's postion up when the keyboard appears ("duck the keyboard" animation), and down back again when the keyboard is dismissed, but only on devices where actual overlap occurs (i.e., smaller screens), by checking the keyboard's dimensions (passed along the UIKeyboardWillShowNotification
notification) against those of the main view and the panel.
I had completely forgotten about that one because I was testing on the iPhone 6 simulator, which screen size causes only minimal (almost imperceptible, but nevertheless present) keyboard overlap and hence panel adjustment animation. When I tried the code on the iPhone 6+ simulator (where the keyboard-ducking animation is skipped altogether because no overlapping occurs), the problem disappeared completely and all animations behaved as expected.
This other restore-panel-after-ducking-the-keyboard animation is no longer needed in my code, because the only way to dismiss the keyboard is when valid credentials have been entered, and autnentication begins (lowering the panel all the way down, off-screen). The panel only reappears if the entered credentials failed to be authenticated on the server side.
Upvotes: 2