read

This is a Swift code snippet for making the tab bar have a sliding animation when selected.

This post takes reference from the answers on StackOverflow.

The difference:

  • Code in Swift
  • With a private method animateToTab which you can call programatically
  • Less code using frame.center etc

The Code

Hooking up to UITabBarControllerDelegate, you can start the animation when a tab is about to be selected:

func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
    let tabViewControllers = tabBarController.viewControllers!
    guard let toIndex = tabViewControllers.indexOf(viewController) else {
        return false
    }
    
    // Our method
    animateToTab(toIndex)
    
    return true
}

We have our method animateToTab, which contains the bulk of the code for animating the views.

Remember: You can even call animateToTab programmatically to switch tab, with the same sliding animation.

func animateToTab(toIndex: Int) {
    let tabViewControllers = viewControllers!
    let fromView = selectedViewController!.view
    let toView = tabViewControllers[toIndex].view    
    let fromIndex = tabViewControllers.indexOf(selectedViewController!)
    
    guard fromIndex != toIndex else {return}
    
    // Add the toView to the tab bar view
    fromView.superview!.addSubview(toView)
    
    // Position toView off screen (to the left/right of fromView)
    let screenWidth = UIScreen.mainScreen().bounds.size.width;
    let scrollRight = toIndex > fromIndex;
    let offset = (scrollRight ? screenWidth : -screenWidth)
    toView.center = CGPoint(x: fromView.center.x + offset, y: toView.center.y)

    // Disable interaction during animation
    view.userInteractionEnabled = false
    
    UIView.animateWithDuration(0.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
        
            // Slide the views by -offset
            fromView.center = CGPoint(x: fromView.center.x - offset, y: fromView.center.y);
            toView.center   = CGPoint(x: toView.center.x - offset, y: toView.center.y);
            
        }, completion: { finished in
            
            // Remove the old view from the tabbar view.
            fromView.removeFromSuperview()
            self.selectedIndex = toIndex
            self.view.userInteractionEnabled = true
        })
}

A Lesson Learnt

In one of the answers (also swift code), the author uses CA transformation, instead of changing the frames.

That doesn’t work in some cases eg. triggered animateToTab programmatically

I suspect it is the same as the embarrassing problem whereby the animation completed prematuring, because iOS “don’t see any animation” to do. In the completion block, finished will be false, which would mean the animation wasn’t completed.

I do not know exactly how to fix the code, but changing to frames work.

Do you know what’s wrong?


Image

@samwize

¯\_(ツ)_/¯

Back to Home