プログラミング

【Swift】UITabeBarControllerとUINavigationControllerをコードで実装する

swift-eyecatch

同じstoryboardにUIViewControllerをたくさん配置したりすると、storyboardがかなり重くなりませんか?

storyboardを使ったほうが早いのは早いのですが、せっかくなので全てコードのみで実装していくのも悪くありません。

さらに、今はまだ厳しい部分が多いですが、将来的に全てSwiftUIに切り替えていくことも踏まえると、全てコードのみで実装していきたいなと思うようになりました。ということで直近のプロジェクトではUIも全てコードで実装しています。

storyboardが重くて動かなかったり、謎のレンダリングエラーがなくなってスッキリ。

やってみるとそこまで難しいことはありません。ただ、UIのためのコードとロジックを切り分ける、ということであったり、複雑なUIだとAutoLayoutのコード量が多くなってしまったりと考えることは出てくるのですが。

今回の記事では、UITabBarControllerとUINavigationControllerを全てコードのみで実装するサンプルを記載しています。

UITabBarControllerとUINavigationControllerのコードの全体像

import UIKit

class CustomTabBarController: UITabBarController {

    private let vc1: SomeViewController = {
        let vc = SomeViewController()
        let image = UIImage(named: "some_icon")
        vc.tabBarItem = UITabBarItem(title: "タブ1", image: image, selectedImage: image)
        return vc
    }()
    private let vc2: SomeViewController = {
        let vc = SomeViewController()
        let image = UIImage(named: "some_icon")
        vc.tabBarItem = UITabBarItem(title: "タブ2", image: image, selectedImage: image)
        return vc
    }()
    private let vc3: SomeViewController = {
        let vc = SomeViewController()
        let image = UIImage(named: "some_icon")
        vc.tabBarItem = UITabBarItem(title: "タブ3", image: image, selectedImage: image)
        return vc
    }()
    private let vc4: SomeViewController = {
        let vc = SomeViewController()
        let image = UIImage(named: "some_icon")
        vc.tabBarItem = UITabBarItem(title: "タブ4", image: image, selectedImage: image)
        return vc
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        let size = CGSize(width: self.view.frame.width, height: 0.1)
        let topLine = UIImage.image(color: .gray, size: size)

        tabBar.tintColor = .blue
        tabBar.backgroundColor = .white
        tabBar.unselectedItemTintColor = .gray
        tabBar.shadowImage = topLine
        tabBar.isTranslucent = false

        let vcs = [vc1, vc2, vc3, vc4]
        let viewControllers = vcs.map{ UINavigationController(rootViewController: $0)}
        setViewControllers(viewControllers, animated: false)
    }
}

名前は何でも良いと思いますが、今回はCustomTabBarControllerという名前で作成します。このCustomTabBarControllerUITabBarControllerを継承しています。

変数にタブに紐付けるUIViewControllerをもたせ、viewDidLoadsetViewControllersします。

このとき、各UIViewControllerrootとしたUINavgationControllerを作成しています。

これでCustomTabBarControllerは完成です。

AppDelegateの設定

コードの全体像は以下の通りです。

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        self.window = UIWindow(frame: UIScreen.main.bounds)
        window!.rootViewController = CustomTabBarController()
        window!.makeKeyAndVisible()

        return true
    }
}

ポイントのみ記載していますが、まずはUIWindowの作成、そして上記で実装したCustomTabBarControllerwindowrootViewControllerに設定しています。最後に、makeKeyAndVisible()で表示します。

storyboardでポチポチ設定するのも良いのですが、UITabBarControllerやUINavigationControllerはコードで実装したほうが早い気がします。

storyboardEmbedをクリックするのにも疲れました。

ただ、最初の内は素直にstoryboardを使ったほうがわかりやすいかなと思うので、理解が進んだらコードのみでの実装も挑戦してみると良さげです。

今回は以上です。