👂

animated-tab-barを使ってタブバーアイコンのアニメーションを実装する

2021/01/05に公開

概要

UITabBarControllerの下に表示されるアイコンを選択したときにアニメーションをつけたいと思い少し調べた所、Viewを再帰的に見ないといけない等で大変そうな印象でした。

そこで今回はお手軽にanimated-tab-barを使って下記のような動きをする実装を試してみました。

image

参考

実装

Ramotion/animated-tab-barのREADME通りCocoapodsで導入します

pod 'RAMAnimatedTabBarController'

初めにUITabBarControllerの代わりにRAMAnimatedTabBarControllerのカスタムクラスを作成します。

import RAMAnimatedTabBarController

class MainTabController: RAMAnimatedTabBarController {
// ~
}
  • 今回はself.viewControllersUINavigationControllerを入れ込みます。
  • このときUINavigationControllerUITabBarItemRAMAnimatedTabBarItemを指定し、アニメーションを設定します。
    • アニメーションは後で作成するRAMMyBounceAnimationを指定しておきます。
func templateNavigationController(image: UIImage?, selectedImage: UIImage? = nil, rootViewController: UIViewController) -> UINavigationController {
    let nav = UINavigationController(rootViewController: rootViewController)
    let animatedTabBarItem = RAMAnimatedTabBarItem(title: nil, image: image, selectedImage: selectedImage)
    animatedTabBarItem.animation = RAMMyBounceAnimation()  // オーバライドしたアニメーションクラスを適用させる
    nav.tabBarItem = animatedTabBarItem
    nav.navigationBar.barTintColor = .white
    
    return nav
}
  • 参考までに、上記は下記の通り使用しています。
func configureViewControllers() {
    
    let feed = FeedController(collectionViewLayout: UICollectionViewFlowLayout())
    let nav1 = templateNavigationController(image: UIImage(systemName: "house"),
                                            selectedImage: UIImage(systemName: "house.fill"),
                                            rootViewController: feed)
    
    let list = ListController(collectionViewLayout: UICollectionViewFlowLayout())
    let nav2 = templateNavigationController(image: UIImage(systemName: "doc.plaintext"),
                                            rootViewController: list)
    
    let search = SearchController(style: .plain)
    let nav3 = templateNavigationController(image: UIImage(systemName: "magnifyingglass"),
                                            rootViewController: search)
    
    viewControllers = [nav1, nav2, nav3]
    self.setSelectIndex(from: 0, to: 1)
}
  • 続いてカスタムのアニメーションクラスRAMMyBounceAnimationを作成します。
    • デフォルトのRAMBounceAnimationがちょっと気にいらなかったので…
  • 基本的にRAMBounceAnimationのコードをコピペしているだけで、アニメーションの時間と拡大縮小のコマ割りの設定だけ変更しています。
import RAMAnimatedTabBarController

class RAMMyBounceAnimation: RAMItemAnimation {
    
    // MARK: - Properties
    
+    private let costomDuration: CGFloat = 0.2
    
    // ...
    
    func playBounceAnimation(_ icon: UIImageView) {
+        let bounceAnimation = CAKeyframeAnimation(keyPath: "transform.scale")
+        bounceAnimation.values = [0.9, 0.8, 0.9, 1.0]
+        bounceAnimation.duration = TimeInterval(costomDuration)
        // ...
    }
}
  • また今のままでは、選択されているタブバーアイコンを再度選択した場合はアニメーションがつきません。
  • そのためUITabBarControllerDelegateを利用して、同じアイコン選択時もアニメーションが表示されるようにします。
    • ただRAMAnimatedTabBarControllerprivate func handleSelection(index: Int)をOverrideするのが本筋かもしれません。
class MainTabController: RAMAnimatedTabBarController {
    
    // MARK: - Properties
    
    private var previousTabBarItemIndex = 0
    private var nextTabBarItemIndex     = 0
    // ...
}


// MARK: - UITabBarControllerDelegate

extension MainTabController: UITabBarControllerDelegate {
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        previousTabBarItemIndex = tabBarController.selectedIndex
        
        return true
    }
    
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        nextTabBarItemIndex = tabBarController.selectedIndex
        
        guard previousTabBarItemIndex == nextTabBarItemIndex,
              let tabBarItem = viewController.tabBarItem as? RAMAnimatedTabBarItem else {
            return
        }
        
        tabBarItem.playAnimation()
    }
}

課題

SelectedImageが機能しない

Discussion