TabBarControllerを用いたXLPagerTabStripの実装

# はじめに

[XLPagerTabStrip](https://github.com/xmartlabs/XLPagerTabStrip)というSwift製のiOSライブラリを使った際に、`TabBarController`と絡めた実装をしました。`storyboard`での設定等で少し詰まったりもしましたので、備忘録として投稿します。

# 動作環境
【Xcode】Version 12.0.1
【Swift】Version 5.3
【CocoaPods】version 1.9.3

# 実装後の画面
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/37b5cafa-f061-ca16-7bb9-7faede36b63c.gif)

# 実装手順
## 1. `TabBarController`の用意
1. `Main.storyboard`の元々ある`ViewController`を削除して、`TabBarController`を追加します。付属の`ViewController`も消しておいてください。（`storyboard`1つに対して`ViewController`1つとする理由です。）
![スクリーンショット 2020-11-08 1.45.48（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/d3486f4a-9105-1882-55c5-f94f2ab7ad70.png)

2. `Is Initial View Controller`にチェックを入れます。
![スクリーンショット 2020-11-08 1.46.33（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/9dd3e5a2-e5c2-47cc-3bc5-9bc9c6152255.png)

3. `MainTabBarController.swift`を作成し、`Main.storyboard`の`Class`に割り当ててください。

```Swift:MainTabBarController.swift
class MainTabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // 各画面となるViewControllerを格納する変数を用意
        var viewControllers = [UIViewController]()

        // それぞれの画面の設定(tabの画像など)
        let tab1VC = UIStoryboard(name: "Bookmarks", bundle: nil).instantiateInitialViewController()
        tab1VC?.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 0)
        viewControllers.append(tab1VC!)

        let tab2VC = UIStoryboard(name: "Favorites", bundle: nil).instantiateInitialViewController()
        tab2VC?.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
        viewControllers.append(tab2VC!)
        
        self.setViewControllers(viewControllers, animated: false)
    }
}
```


## 2. 各画面となる`ViewController`の用意
* 上記の`tab1VC`を`Bookmarks.storyboard`、`tab2VC`を`Favorites.storyboard`として用意します。それぞれ`UINavigationController`を設定し、見分けがつくようにタイトルを付けます。
![スクリーンショット 2020-11-08 2.12.25（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/e60d190b-a09f-6a9a-c3c5-7202feb3fe0c.png)


## 3. `XLPagerTabStrip`を導入
* CocoaPodsを利用します。

1. ターミナルを開いて`cd 対象ファイル`で移動します。
2. `pod init`で`podfile`作成
3. `podfile`に下記を追加し保存して、`pod install`にて完了です。

```podfile.rb
pod 'XLPagerTabStrip'
```


## 4. 管理元クラス`ButtonBarPagerTabStripViewController`の用意
* `ViewController`たちを管理する`ButtonBarPagerTabStripViewController`を継承したクラスを用意します。今回は`Bookmarks`を管理元とします。`BookmarksViewController.swift`を作成します。

```Swift:BookmarksViewController.swift
import UIKit
import XLPagerTabStrip

// 継承元を書き換える （ UIViewController → ButtonBarPagerTabStripViewController ）
class BookmarksViewController: ButtonBarPagerTabStripViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
        //管理されるViewControllerを返す処理
        let firstVC = UIStoryboard(name: "First", bundle: nil).instantiateViewController(withIdentifier: "First")
        let secondVC = UIStoryboard(name: "Second", bundle: nil).instantiateViewController(withIdentifier: "Second")
        let thirdVC = UIStoryboard(name: "Third", bundle: nil).instantiateViewController(withIdentifier: "Third")
        let childViewControllers:[UIViewController] = [firstVC, secondVC, thirdVC]
        return childViewControllers
    }

}
```
#### 1. ボタン部分になる`Collection View`の設置
* ボタン部分になる`Collection View`を配置し、下記画像のように`AutoLayout`を設定します。`Cell`は消しておきましょう。
* `Collection View`のクラスを`ButtonBarView`と結びつけ、Moduleを`XLPagerTabStrip`とします。
![スクリーンショット 2020-11-08 2.33.16（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/8609f788-ded2-864b-ee06-2c13b1094941.png)

* `Collection View`を右クリックします。`Referencing Outlets`の`New Referencing Outlet`を `ViewController`にドラッグし、`ButtonBarView`を選択します。
![スクリーンショット 2020-11-08 3.15.15（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/972d235a-20a9-6fc8-8095-944ccda68c80.png)

#### 2. 切り替え部分になる`ScrollView`の設置
* 切り替え部分になる`ScrollView`を配置し、下記画像のように`AutoLayout`を設定します。
* あいまいなレイアウトと警告がでるので`Content Layout Guides`のチェックを外しましょう。

![スクリーンショット 2020-11-08 2.35.37（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/efb7050f-df30-fa76-508f-b016d4b60d0c.png)

* `ScrollView`を右クリックします。`Referencing Outlets`の`New Referencing Outlet`を `ViewController`にドラッグし、`containerView `を選択します。
![スクリーンショット 2020-11-08 2.54.55（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/e7c0aa54-93c6-10b0-35b4-11fd0de4bb68.png)

* 正しく繋ぐことができると、`ScrollView`の表示が`ContainerView`に変わります。


## 5. 管理される`ViewController`たちの用意
* スワイプやボタンを押されて遷移する`ViewController`になります。
* `IndicatorInfoProvider`プロトコルを実装した`UIViewController`を下記3つそれぞれ用意します。

1. `First.storyboard`、`FirstViewController`を用意。（ `storyboard`の背景色は`赤色` ）
2. `Second.storyboard`、`SecondViewController`を用意。（ `storyboard`の背景色は`青色` ）
3. `Third.storyboard`、`ThirdViewController`を用意。（ `storyboard`の背景色は`緑色` ）

```Swift:FirstViewController.swift
import UIKit
import XLPagerTabStrip

class FirstViewController: UIViewController {
    
    //ここがボタンのタイトルに利用されます
    var itemInfo: IndicatorInfo = "First"

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

extension FirstViewController: IndicatorInfoProvider {
    func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
        return itemInfo
    }
}
```

* `Label`を配置し、`Text`を__First__、`Font`を__24__、`AutoLayout`の設定をします。
![スクリーンショット 2020-11-08 2.59.11（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/45a55e83-2b41-d31b-e158-c0726307303b.png)

* `Class`の割り当てと、`Storyboard ID`を設定します。
![スクリーンショット 2020-11-08 3.13.26（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/bfb326eb-5c21-1dfe-77d7-b03bc0928a14.png)


## 6. buttonBarの見た目と振る舞いを追加

```Swift:MainTabBarController.swift
import UIKit
import XLPagerTabStrip

class BookmarksViewController: ButtonBarPagerTabStripViewController {

    override func viewDidLoad() {
        // 画面UIについての処理
        setupUI()
        super.viewDidLoad()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 強制的に再選択し、changeCurrentIndexProgressiveを動作させる（ 0番目 → 1番目 → 0番目 ）
        moveToViewController(at: 1, animated: false)
        moveToViewController(at: 0, animated: false)
    }
    
    func setupUI() {
        // ButtonBar全体の背景色
        settings.style.buttonBarBackgroundColor = UIColor.white
        // ButtonBarItemの背景色
        settings.style.buttonBarItemBackgroundColor = UIColor.white
        // ButtonBarItemの文字色
        settings.style.buttonBarItemTitleColor = UIColor.lightGray
        // ButtonBarItemのフォントサイズ
        settings.style.buttonBarItemFont = .boldSystemFont(ofSize: 14)
        // 選択中のButtonBarインジケーターの色
        settings.style.selectedBarBackgroundColor = UIColor.black
        // 選択中のButtonBarインジケーターの太さ
        settings.style.selectedBarHeight = 2.0
        // ButtonBarの左端の余白
        settings.style.buttonBarLeftContentInset = 8
        // ButtonBarの右端の余白
        settings.style.buttonBarRightContentInset = 8
        // Button内の余白
        settings.style.buttonBarItemLeftRightMargin = 32
        // スワイプやButtonBarItemタップ等でページを切り替えた時の動作
        changeCurrentIndexProgressive = { oldCell, newCell, progressPercentage, changeCurrentIndex, animated in
            // 変更されたか、選択前後のCellをアンラップ
            guard changeCurrentIndex, let oldCell = oldCell, let newCell = newCell else { return }
            // 選択前のセルの状態を指定
            oldCell.label.textColor = UIColor.lightGray
            // 選択後のセルの状態を指定する
            newCell.label.textColor = UIColor.black
        }
    }
    
    override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
        //管理されるViewControllerを返す処理
        let firstVC = UIStoryboard(name: "First", bundle: nil).instantiateViewController(withIdentifier: "First")
        let secondVC = UIStoryboard(name: "Second", bundle: nil).instantiateViewController(withIdentifier: "Second")
        let thirdVC = UIStoryboard(name: "Third", bundle: nil).instantiateViewController(withIdentifier: "Third")
        let childViewControllers:[UIViewController] = [firstVC, secondVC, thirdVC]
        return childViewControllers
    }

}

```


# 参考
* [UITabBarControllerとUINavigationControllerをコードで作る](https://qiita.com/koooooo/items/bff30c8a2e77451864a1)
* [[Swift 5] ライブラリ「XLPagerTabStrip」の使い方（導入）](https://qiita.com/Riscait/items/88a5f6c11ce42e6f6624)