UIView animation acting weird - swift

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"?

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.

Related

Select the first element in view for Voice Over

I am using Xcode to make an iOS app. When I segue into the next view controller, it has objects in the following order from top to bottom on the screen: label, collection view, button. When I use voiceover, I want the first item on the screen to be in focus (the label). However, whatever I do, it is always a particular cell from the collection view that is selected by default (somewhere in the middle of the screen). In landscape it is a different cell and in portrait a different cell. But every time it is that same cell. I tried using UIAccessibilityPostNotification, as well as using delays and other things. Nothing seems to work.
Should be posted when a new view appears that encompasses a major portion of the screen.
Optionally, pass the element that VoiceOver should move to after processing the notification.
UIKIT_EXTERN UIAccessibilityNotifications
UIAccessibilityScreenChangedNotification;
You need to provide
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, youLabel);

inserted button is not visible. Constrained Layout

When I drag and drop button in design mode. The button is not shown. why?
it is in top left corner.
Make sure the view has constraints set.
Otherwise, it behaves this way - AS even tells you.
This view is not constrained. It only has designtime positions, so it will jump to (0,0) at runtime...

How does the UIScrollView delegate know about my UIScrollView ivar?

I'm working on a app that has a paging UIScrollView that contains three scrollViews as subviews which display images that you can pinch and zoom on. The code came from Apple's "PhotoScroller" sample code but I've stripped out the tiling functionality because I'm trying to master the basics first.
I can zoom in on my different images and page through them, which is great. When I leave an image that has been zoomed in to go to the next "page" of the pagingScrollView I want it to be restored to it's original zoom size, right now it stays at the zoom level that I left it at.
I imagine I need to write some code that tells the zoomed UIScrollView to go back to the appropriate zoom scale when I get to the next page. My question is how do I do that?
So far I've been working with UIScrollView's Delegate method "scrollViewDidScroll" and and the "contentOffset" property. Another thought is somehow getting a notification that the pagingScrollView has moved to the next "page."
Any ideas?
If you're interested in knowing when the scroll view has stopped (e.g. the user has let go and the scroll view has snapped into position on a new page) you can use scrollViewDidEndDecelerating:. However, the user may scroll several pages before allowing the scroller to fully stop, so the last page the user stopped on may not be the immediately preceding or immediately following page. You can keep a pointer to the current page and each time the user stops on a page restore the previously current page to the default zoom level before updating the current page pointer.

How to implement a cyclic UIScrollView?

How to implement a cyclic UIScrollView? That is to say, when you scroll to the very left item then the UIScrollView will show the very right one. Any help would be appreciate.
Sure, you need three views. At any given time you have a left view, a right view and a current view.
This requires notification of each movement through the UIScrollViewDelegate.
If you detect that you moved right, you free left, make left = current, current = right, and make a new right.
If you detect that you moved left, you free right, make right = current, current = left, and make a new left.
Generally speaking, any view that is more than one page away from current is not required. So you need only three pages in total.
Of course you also need to manipulate the position of the UIScrollView so you can make the movements - the net result is you don't move although it looks like you have. When you have done the scroll, and altered the views according to the left/current/right shuffle - you do
[self scrollRectToVisible:(middle frame) animated:NO];
so that you are always looking at the same actual page, with one page each side of it. When the scroll happens it looks like the user can keep scrolling around in a loop - but after each page ticks over, the views are shuffled, the position within the scroll view gets set back to the middle and the user can scroll again.
Getting back to the start is simply a matter of using the view related to whatever object is at the other end of whatever data structure you are using - so if current = [(NSArray)data lastObject] then right = [(NSArray)data objectAtIndex:0].

adding a textbox and a button at the top of the keyboard on iphone

I want to add a text box and a button beside it. They will be at the bottom of the window. Then, when I touch the textbox (to type something), keyboard will appear and the whole row (with textbox and button) scrolls up and the keyboard will be right below them. Could you please let me know how can I do that?
Is there any sample program?
Thanks.
Matt Gallagher posted this on his blog:
Sliding UITextFields around to avoid the keyboard
It is a step by step example of exactly what you want.
In the XCode documentation iPhone Application Programming Guide there is a section on "Moving Content That Is Located Under the Keyboard" that talks about receiving keyboard notifications when a keyboard is about to show. There's code there to show you how to get the keyboard size (which varies depending on the orientation). I won't repeat it here.
You can use the same technique to get the UIKeyboardWillShowNotification notification and get the height of where the keyboard will end up. That gives you the bottom edge of where your view needs to go, effectively putting it above the keyboard. So just put your textbox and button inside a view. When you get the notification tell your view where it needs to go (keyboard height + height of the container view) and you're done. You'll also want to catch UIKeyboardWillHideNotification to move the view back to where it was, so keep track of the original container view position.
It's pretty straightforward and it'll look nice, especially if you use a nice UIView animation effect and set the timing just right.