0

I have a video player that has a standard toolbar. The toolbar is dismissed by a swipe down gesture. I also have a view (a panel really) that can appear directly above the toolbar and is also dismissed by a swipe down gesture. When both the panel and the toolbar are open, one swipe down gesture should dismiss the panel, a second will dismiss the toolbar. Problem is that when the swipe gestures occur quickly back-to-back (before the panel animation completes) then the toolbar animation jitters.

- (void)handleSwipe:(UISwipeGestureRecognizer *)gestureRecognizer
{
    UISwipeGestureRecognizerDirection direction = [gestureRecognizer direction];

    if (direction == UISwipeGestureRecognizerDirectionDown) {
        if (![toolbar isHidden]) {
            // Only dismiss the bottom panel if it is open
            if (_selectedSegmentIndex != UISegmentedControlNoSegment) {
                _selectedSegmentIndex = UISegmentedControlNoSegment;
                [bottomPanelView dismissPanel];
            } else {
                CGRect tempRect = CGRectMake(0, self.view.frame.size.height, toolbar.frame.size.width, toolbar.frame.size.height);
                [UIView animateWithDuration:0.25f
                                 animations:^{
                                    // Move the toolbar off the screen.
                                    toolbar.frame = tempRect;
                                 }
                                 completion:^(BOOL finished) {
                                     [toolbar setHidden:YES];
                                 }];
            }
        }
    }
}

[bottomPanelView dismissPanel] is in a separate class and is not aware of the class that calls it. It has the follow animation...

[UIView animateWithDuration:self.panelAnimationDuration
                      delay:0.0
                    options:UIViewAnimationOptionCurveLinear
                 animations:^{
                     // slideOutLocation is off the screen 
                     self.view.frame = slideOutLocation;
                 }
                 completion:^(BOOL finished) {
                     [self.view removeFromSuperview];
                     [self removeFromParentViewController];
                     self.panelActive = NO;
                 }];

So basically, the dismissPanel animation is still running when the animation to dismiss the toolbar begins. When performing a double swipe in slow motion in the simulator, the first animation looks fine, but the toolbar animation is jittery.

I know how to nest animations in the completion block, but that cannot be done here since dismissing both the panel and the toolbar is not always what is wanted. Also, the dismissPanel code is handled elsewhere and is not in control of the toolbar.

Is there a way to allow multiple animation blocks to run simultaneously without putting the completion block? Let me know if any clarification is needed! Thanks!

timgcarlson
  • 3,017
  • 25
  • 52
  • I think when you get the second swipe you should stop the first animation. See the answer here: http://stackoverflow.com/questions/554997/cancel-a-uiview-animation. Then you can start the other animation to make it go back and it won't really matter where it currently is. – jraede Dec 06 '13 at 00:06
  • I've tried removing the animations using `removeAllAnimations` as one of the users in that post mentioned. Even though I'm running `removeAllAnimations` on the panel's view, it seems to prevent my toolbar from animating because the toolbar just disappears on the second swipe, instead of sliding down off the screen. – timgcarlson Dec 06 '13 at 00:50

1 Answers1

1

I wonder if the problem might have to do with auto layout (setting frames while auto layout is on causes problems). I tried a simple test of animating a view and a tool bar off the bottom of the screen by animating their constraint constants, and the animation looked fine. I made IBOutlets to their respective bottom constraints (called viewBottomCon and toolBarBottomCon).

- (void)viewDidLoad {
    [super viewDidLoad];
    self.isFirstSwipe = YES;
}

-(IBAction)downSwipe:(UISwipeGestureRecognizer *)sender {
    if (self.isFirstSwipe) {

        self.viewBottomCon.constant = -52;
        self.isFirstSwipe = NO;
        [UIView animateWithDuration:5 animations:^{
            [self.view layoutIfNeeded];
        } completion:nil];

    }else if (!self.isFirstSwipe) {

        self.toolBarBottomCon.constant = -44;
        [UIView animateWithDuration:3 animations:^{
            [self.view layoutIfNeeded];
        } completion:nil];
    }
}

This is a simpler setup than yours, but I think it should work in your case too.

rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • Well wouldn't you know it, turning Auto Layout off fixed the issue. I previously had Auto Layout on for positioning certain items on the toolbar, but everything is good with it off. I've started to experiment with trying your method of manipulating the constraints, but given that I've been building everything without them for a while now, there is much work to be done to switch over to using them on everything. Perhaps I will need to do a refactoring later on to us Auto Layout exclusively... – timgcarlson Dec 06 '13 at 19:21