2
votes

I am attempting to animate a tab bar to move from below the bottom of the screen to the top while simultaneously adjusting a view's height to shrink by the height of the tab bar. Essentially, I have a "hidden" tab bar that when it unhides should animate into view and the displayView should adjust for the space the tab bar now takes up.

However, the animation is jumpy for the display view. It seems that the display view animates fine, but the subviews automatically adjust their height without any animation. Any direction on fixing this would be appreciated.

I will accept aid in either objective-c or swift, as the translation is fairly easy.

 //Displays tab bar with slide up animation. If animated is false, all other params are unused
        func displayTabBar(animated:Bool, duration:NSTimeInterval = 0.5, delay:NSTimeInterval = 0, options:UIViewAnimationOptions = UIViewAnimationOptions.CurveLinear, completion:((Bool) -> Void)? = nil){
            if(animated){
                UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
                        self.adjustTabBarDisplayed()
                    }, completion: completion)
                UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
                        self.adjustDisplayViewTabDisplayed()
                    }, completion: nil)
            }
            else{
                self.adjustTabBarDisplayed()
                self.adjustDisplayViewTabDisplayed()
            }

        }

        //Adjusts frame of tab bar to display tab bar
        private func adjustTabBarDisplayed(){
            self.tabBar.frame = CGRectMake(0,UIScreen.mainScreen().bounds.height - self.tabBar.bounds.height, self.tabBar.bounds.width, self.tabBar.bounds.height)
        }

        //Adjusts frame of display view to match displayed tab bar
        private func adjustDisplayViewTabDisplayed(){
            self.displayView.frame = CGRectMake(0,0,self.displayView.bounds.width, UIScreen.mainScreen().bounds.height - self.tabBar.bounds.height)
        }
2

2 Answers

7
votes

When you modify a view's size, it doesn't lay out its subviews immediately. Instead, it sets a flag indicating that it needs layout. Later, after the system has finished dispatching the event that ended up calling displayTabBar, it runs the display refresh code. The display refresh code finds views that have the needs-layout flag set and tells them to lay themselves out (by sending them layoutSubviews).

Here, you are changing your display view's size inside an animation block. Therefore change to your display view's frame will be animated. But the frames of its subviews are changing outside the animation block; they're changing later during the layout phase. You need to make them change inside the animation block.

Lucky for you, that's easy. Just call self.displayView.layoutIfNeeded() inside the animation block. Also, you only need one animation block, since all of the animation parameters are identical:

func displayTabBar(animated:Bool, duration:NSTimeInterval = 0.5, delay:NSTimeInterval = 0, options:UIViewAnimationOptions = UIViewAnimationOptions.CurveLinear, completion:((Bool) -> Void)? = nil){
    if(animated){
        UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
                self.adjustTabBarDisplayed()
                self.adjustDisplayViewTabDisplayed()

                // ADD THIS LINE
                self.displayView.layoutIfNeeded()
            }, completion: completion)
    }
    else{
        self.adjustTabBarDisplayed()
        self.adjustDisplayViewTabDisplayed()
    }
}
0
votes

Use the below line of code in animation block

scrollView.layoutIfNeeded()