Long story short, I have a view controller where the user can tap on self.view
(anywhere but the nav bar) and it will enter a full screen mode where the controls at the bottom fade out and the navigation and status bar fade out. Similar to iBooks.
I could simply fade the alpha of the navigation bar, but as to allow the user to tap in the newly gained area (where the navigation bar was now that it's faded out) and have it do something, I have to do more than change the alpha, as the nav bar is still technically there taking up area.
So I hide the navigation bar with [self.navigationController setNavigationBarHidden:YES animated:NO];
. I have to do this after the animation block finishes, else it will be in the animation block and animate as part of the block. So I use a dispatch_after
to make it finish after the animation completes (0.35 second delay).
However, this causes the issue where if the user taps any time during that 0.35 second time period where it's animating out and things are waiting to be finished, it causes glitchy behaviour where another block starts even though it's still waiting 0.35 seconds for the other one to finish. It causes some glitchy behaviour and causes the navigation bar to stay hidden. Gross.
Video of it happening: http://cl.ly/2i3H0k0Q1T0V
Here's my code to demonstrate what I'm doing:
- (void)hideControls:(BOOL)hidden {
self.navigationController.view.backgroundColor = self.view.backgroundColor;
int statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
[UIView animateWithDuration:0.35 animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationFade];
if (hidden) {
self.navigationController.navigationBar.alpha = 0.0;
self.instructionsLabel.alpha = 0.0;
self.backFiftyWordsButton.alpha = 0.0;
self.forwardFiftyWordsButton.alpha = 0.0;
self.WPMLabel.alpha = 0.0;
self.timeRemainingLabel.alpha = 0.0;
}
else {
self.navigationController.navigationBar.alpha = 1.0;
self.instructionsLabel.alpha = 1.0;
self.backFiftyWordsButton.alpha = 1.0;
self.forwardFiftyWordsButton.alpha = 1.0;
self.WPMLabel.alpha = 1.0;
self.timeRemainingLabel.alpha = 1.0;
}
[self.view layoutIfNeeded];
}];
// Perform an "actual" hide (more than just alpha changes) after the animation finishes in order to regain that touch area
if (hidden) {
double delayInSeconds = 0.35;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[self.navigationController setNavigationBarHidden:YES animated:NO];
self.textToReadLabelPositionFromTopConstraint.constant = TEXT_LABEL_DISTANCE + self.navigationController.navigationBar.frame.size.height + statusBarHeight;
});
}
else {
[self.navigationController setNavigationBarHidden:NO animated:NO];
self.textToReadLabelPositionFromTopConstraint.constant = TEXT_LABEL_DISTANCE;
}
}
The only other thing I'm doing is changing the constant on my Auto Layout constraint to account for the navigation bar and status bar dependent on whether or not they're there.
I'm not sure how to factor in the fact that double tapping can really glitch out the full screen process. How could I make it so if they tap during the animation process it will just cancel the animation and do their desired action as intended? Could I be doing this process better?
self.navigationController.navigationBar.userInteractionEnabled = NO;
if you want to block user interactions on that view during the animation. – nst Aug 6 '13 at 16:35UINavigationBar
subclass and overridehitTest:withEvent:
so the navbar ignores touches while it is invisble. Your views below the navbar should still receive these touches. – XJones Aug 6 '13 at 23:37