2021年10月3日日曜日

UITabBarAppearanceを使って、TabBarの配色をセットする

iOS13以降のTabBarのカスタマイズです。
今回の記事では、次のようにTabBarをカスタマイズしました。

1. UITabBarを継承した、カスタムViewを作成する
2. TabBarItemの配色をUITabBarItemAppearanceで作成する
3. UITabBarAppearanceを生成する
4. UITabBarにセットする
5. UITabBarViewControllerにて、カスタムViewを使う


UITabBarを継承した、カスタムViewは次になります。

final class MyUITabBar: UITabBar {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    private enum Const{
        static let backgroundColor: UIColor = .systemGroupedBackground
        static let tintColor: UIColor = .gray
        static let selectedColor: UIColor = .black
    }
    
    private func setupView() {
        let tabBarItemAppearance = setupTabBarItemAppearance()
        let appearance = UITabBarAppearance()
        appearance.configureWithOpaqueBackground()
        appearance.backgroundColor = Const.backgroundColor
        appearance.stackedLayoutAppearance = tabBarItemAppearance
        appearance.inlineLayoutAppearance = tabBarItemAppearance
        appearance.compactInlineLayoutAppearance = tabBarItemAppearance

        standardAppearance = appearance
        // iOS15: we need to set
        scrollEdgeAppearance = appearance
    }

    private func setupTabBarItemAppearance() -> UITabBarItemAppearance {
        let tabBarItemAppearance = UITabBarItemAppearance()
        // for normal
        tabBarItemAppearance.normal.iconColor = Const.tintColor
        tabBarItemAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: Const.tintColor]
        
        // for selected
        tabBarItemAppearance.selected.iconColor = Const.selectedColor
        tabBarItemAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: Const.selectedColor]
        
        return tabBarItemAppearance
    }
}

UITabBarControllerの子となる各ViewControllerでは、次のようにtabBarItemを指定するのみです。
tabBarItemと配色をするAppearanceをコード上で分け、責務が分離できるので非常に見やすいコードとなりました。

final class FirstViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setupTabBar()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    private func setupTabBar() {
        tabBarItem = UITabBarItem(title: "Home", image: UIImage(systemName: "house"), selectedImage: UIImage(systemName: "house"))
    }
}

final class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setupTabBar()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    private func setupTabBar() {
        tabBarItem = UITabBarItem(title: "Trash", image: UIImage(systemName: "trash"), selectedImage: UIImage(systemName: "trash"))
    }

}