JoniVR JoniVR - 1 year ago 125
iOS Question

How to animate Tab bar tab switch with a CrossDissolve slide transition?

I'm trying to create a transition effect on a

UITabBarController
somewhat similar to the Facebook app. I managed to get a "scrolling effect" working on tab switch, but I can't seem to figure out how to cross dissolve (or it doesn't work at least).

Here's my current code:

import UIKit

class ScrollingTabBarControllerDelegate: NSObject, UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {

return ScrollingTransitionAnimator(tabBarController: tabBarController, lastIndex: tabBarController.selectedIndex)
}
}

class ScrollingTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
weak var transitionContext: UIViewControllerContextTransitioning?
var tabBarController: UITabBarController!
var lastIndex = 0

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.2
}

init(tabBarController: UITabBarController, lastIndex: Int) {
self.tabBarController = tabBarController
self.lastIndex = lastIndex
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
self.transitionContext = transitionContext

let containerView = transitionContext.containerView
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)

containerView.addSubview(toViewController!.view)

var viewWidth = toViewController!.view.bounds.width

if tabBarController.selectedIndex < lastIndex {
viewWidth = -viewWidth
}

toViewController!.view.transform = CGAffineTransform(translationX: viewWidth, y: 0)

UIView.animate(withDuration: self.transitionDuration(using: (self.transitionContext)), delay: 0.0, usingSpringWithDamping: 1.2, initialSpringVelocity: 2.5, options: .transitionCrossDissolve, animations: {
toViewController!.view.transform = CGAffineTransform.identity
fromViewController!.view.transform = CGAffineTransform(translationX: -viewWidth, y: 0)
}, completion: { _ in
self.transitionContext?.completeTransition(!self.transitionContext!.transitionWasCancelled)
fromViewController!.view.transform = CGAffineTransform.identity
})
}
}


Would be great if anyone know how to get this to work, been trying for days now without progress... :/

EDIT: I got a cross dissolve working by replacing the UIView.animate block with:

UIView.transition(with: containerView, duration: 0.2, options: .transitionCrossDissolve, animations: {

toViewController!.view.transform = CGAffineTransform.identity
fromViewController!.view.transform = CGAffineTransform(translationX: -viewWidth, y: 0)

}, completion: { _ in

self.transitionContext?.completeTransition(!self.transitionContext!.transitionWasCancelled)
fromViewController!.view.transform = CGAffineTransform.identity

})


However, the animation is really laggy and not usable :(

Answer Source

There is a simpler way to doing this. Add the following code in the tabbar delegate:

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {

    if selectedViewController == nil || viewController == selectedViewController {
        return false
    }

    let fromView = selectedViewController!.view
    let toView = viewController.view

    UIView.transition(from: fromView!, to: toView!, duration: 0.3, options: [.transitionCrossDissolve], completion: nil)

    return true
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download