【iOS】Tabmanを使ってタブ画面を実装する

こんにちは、仙台オフィスでiOSアプリの開発を担当しているはんだです。

iOSアプリで、タブの切り替えによって表示内容を変更する画面を作成する機会があり、Tabmanというライブラリを使って実装しました。

github.com

この記事では、Tabmanの基本的な使い方やレイアウトの設定方法を、画像付きで紹介したいと思います。 多様なオプションが用意されており、かなり柔軟にレイアウトが設定できます。

基本的な使い方

まずはGitHubのREADMEにならって、タブバーを画面に追加します。

import Tabman
import Pageboy

class TabViewController: TabmanViewController {

    // タブで表示するViewControllerを生成(今回はタブ3つ)
    private var viewControllers = [Tab1ViewController(), Tab2ViewController(), Tab3ViewController]

    override func viewDidLoad() {
        super.viewDidLoad()

        self.dataSource = self

        // バーを生成
        let bar = TMBar.ButtonBar()

        // バーを画面の上に設置
        addBar(bar, dataSource: self, at: .top)
    }
}

// DataSourceの設定
extension ViewController: PageboyViewControllerDataSource, TMBarDataSource {

    func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int {
        return viewControllers.count
    }

    func viewController(for pageboyViewController: PageboyViewController,
        at index: PageboyViewController.PageIndex) -> UIViewController? {
            return viewControllers[index]
    }

    func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? {
        return nil
    }

    func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
        var title = ""
        switch index {
        case 0:
            title = "タブ1"
        case 1:
            title = "タブ2"
        case 2:
            title = "タブ3"
        default:
            break
        }
        return TMBarItem(title: title)
    }
}

すると、このようにTMBarItem(title: title)で設定したtitleに応じたタブと、viewControllers[index]に応じた画面が表示されます。

f:id:handah:20210427154828p:plain
カスタマイズしないとこんな見た目

f:id:handah:20210427154917p:plain
別のタブを選択すると画面が切り替わる

画面の切り替えは、タブをタップしても、横にスクロールさせても行うことができます。

カスタマイズ

以降は、レイアウトのカスタマイズ方法を説明していきます。

タブバー全体のスタイリング

先ほどの例ではバーのインスタンスを生成する際に

// バーを生成
let bar = TMBar.ButtonBar()

としていましたが、ButtonBar以外にLineBarTabBarがあります。

// バーを生成
let bar = TMBar.LineBar()

f:id:handah:20210427170352p:plain
テキストがない、インジケータだけのバー

また、TabBarというものもあります。こちらはタブにイメージを設定できます。

// バーを生成
let bar = TMBar.TabBar()

イメージは、barItem(for:at:)TMBarItemを返す際に指定できます。

func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
    var title = ""
    var image: UIImage = UIImage()
    switch index {
        case 0:
        title = "タブ1"
        // 任意のイメージ
        image = UIImage(systemName: "person")!
        (中略)
    }
    return TMBarItem(title: barTitle, image: image)
}

f:id:handah:20210427170949p:plain
アイコンを表示できる

各要素のスタイリング

ここからは、バーを構成している要素についてスタイリングしていきます。ButtonBarの例で見ていきます。

バーはTMBarLayoutTMBarButtonTMBarIndicatorの3つの要素で構成されています。ざっくり説明するとTMBarLayoutはバー全体のスタイルを設定しているクラスで、TMBarButtonはタブのボタンを表すクラス、TMBarIndicatorはタブ下のインジケータを表すクラスです。

はじめに、以降の説明がわかりやすくなるよう各要素に色を設定します。

// 全体の色を.yellowに
bar.backgroundView.style = .flat(color: .yellow)

// タブのボタンの色を.greenに
bar.buttons.customize { button in
    button.backgroundColor = .green
    // buttonの他のカスタマイズについては後述します
}

// インジケータの色を.redに
bar.indicator.backgroundColor = .red

すると、以下のようになります。

f:id:handah:20210427173858p:plain
黄色がバー全体、緑色がTMBarButton、赤色がTMBarIndicator

では、各要素のオプションについて説明していきます。

TMBarLayout

タブの並べ方や、全体の余白などを調節できます。 ここまではタブが左寄せになっていましたが、alignmentを変更するとこれを調整できます。

// 選択中のタブを中央に持ってくる
bar.layout.alignment = .center

f:id:handah:20210427181808p:plain
選択中のタブが中央に

また、バーいっぱいにタブを広げる場合はcontentModeを変更します。

bar.layout.contentMode = .fit

f:id:handah:20210427182254p:plain
各タブが均等に広がる

タブの周りに余白を取りたい場合は、contentInsetを設定します。

bar.layout.contentInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)

f:id:handah:20210427182540p:plain
タブの上下左右に余白ができる

タブの間の余白を調整する場合は、interButtonSpacingを変更します。

bar.layout.interButtonSpacing = 1 // デフォルトは16

f:id:handah:20210428135715p:plain
タブの間隔が狭くなった

TMBarButton

次はタブのボタンをカスタマイズしていきます。先ほど、色を変えたときに

// タブのボタンの色を.greenに
bar.buttons.customize { button in
    button.backgroundColor = .green
}

としました。ここにbuttonの設定を追加していきます。

まずは文字色を変えてみます。選択中のタブだけを別の色にすることもできます。

bar.buttons.customize { button in
    button.tintColor = .blue    // 追加
    button.selectedTintColor = .blue    // 追加
    button.backgroundColor = .green
}

f:id:handah:20210428111704p:plain
タブの文字色が青になった

フォントを変更することもできます。選択しているタブだけを太字にする場合は以下のようにします。

bar.buttons.customize { button in
    button.tintColor = .blue
    button.selectedTintColor = .blue
    button.font = UIFont.systemFont(ofSize: 14)  // 追加
    button.selectedFont = UIFont.boldSystemFont(ofSize: 14)  // 追加
    button.backgroundColor = .green
}

f:id:handah:20210428113411p:plain
選択中のタブのテキストが太字になった

TMBarIndicator

ここからはインジケータをカスタマイズしていきます。

おさらいになりますが、先ほどインジケータの色を変えた際はこのようにしました。

bar.indicator.backgroundColor = .red

overScrollBehaviorというプロパティを変更すると、インジケータを画面端までスライドさせた時の挙動を設定できます。 デフォルトでは、.bounce となっていて、インジケータがバーからはみ出すようになっています。

f:id:handah:20210428115120p:plain
インジケータがバーからはみ出す

こちらを.compressにすると、はみ出さないようにインジケータが圧縮されるような見た目になります。

bar.indicator.overscrollBehavior = .compress

f:id:handah:20210428115233p:plain
インジケータが圧縮されバーからはみ出ない

また、weightプロパティを変更することで、太さが調整できます。

デフォルトでは.mediumとなっているのですが、これを.heavyに変更してみます。なお、.smallが2pt、.mediumが4pt、.heavyが8ptです。

bar.indicator.weight = .heavy

f:id:handah:20210428115621p:plain
インジケータが太くなった

これ以外の太さに設定することもできます。例えば太さを3ptにしたい場合は、以下のようにします。

bar.indicator.weight = .custom(value: 3)

f:id:handah:20210428115815p:plain
インジケータの太さが3ptになる

その他のカスタマイズ

ここまで、ButtonBarのカスタマイズについて説明しました。

詳しくは触れませんが、これまで紹介してきたTMBarLayout, TMBarButton, TMBarIndicatorは、それぞれ用意されているスタイルから自分の好きなものを選んで組み合わせることができます。

// バーを生成
let bar = TMBarView<TMConstrainedHorizontalBarLayout, TMLabelBarButton, TMDotBarIndicator>()

f:id:handah:20210428132154p:plain
例えばインジケータが点で、タブを2つまでしか表示しないタブバーを作ることができる

また、自分で作成したクラスを使ってタブバーを作成することもできます。こちらについては、実際に作成されているプロジェクトが公開されていますので、こちらをご覧ください。

github.com

以上、Tabmanについてのご紹介でした。最後までお読みいただきありがとうございました。