😊

SwiftUIでタブに動きをつける

2024/09/18に公開

今回は、SwiftUIのタブにアニメーションを追加する方法について解説します。TabViewに動きを加えることで、ユーザーにとって視覚的にわかりやすく、インタラクティブなUIを作成できます。この記事では、初心者の方にもわかりやすいように、ソースコードを基に丁寧に説明していきます。

完成イメージ

以下のように、タブを切り替えるときにアイコンが動き、選択されたタブにアニメーションが付与されます。これにより、どのタブが選択されているのかが直感的に分かります。

実装する機能

TabView で複数のタブを表示
選択されたタブにアニメーションを付与
カスタムタブバーの作成

ソースコードの概要

次にソースコードの各部分を説明していきます。

struct TabViewTest: View {
    @State private var activeTab: Tab = .photos
    @State private var allTabs: [AnimatedTab] = Tab.allCases.compactMap { tab -> AnimatedTab? in
        return .init(tab: tab)
    }
    var body: some View {
        VStack(spacing: 0) {
            TabView(selection: $activeTab){
                NavigationStack{
                    VStack{}
                    .navigationTitle(Tab.photos.title)
                }
                .setUpTab(.photos)
                NavigationStack{
                    VStack{}
                    .navigationTitle(Tab.chat.title)
                }
                .setUpTab(.chat)
            }
            CustomTabBar()
        }
    }

ここでは、2つのタブ、Photos と Chat を用意しています。NavigationStack を使うことで、ナビゲーションバーと連携させています。

カスタムタブバーの作成

標準の TabView のタブバーを使わず、独自のデザインとアニメーションを持つカスタムタブバーを作成しています。これが、ユーザーに動きを感じさせる重要な部分です。

@ViewBuilder
func CustomTabBar() -> some View {
    HStack(spacing: 0) {
        ForEach($allTabs) { $animatedTab in
            let tab = animatedTab.tab
            VStack(spacing: 4) {
                Image(systemName: tab.rawValue)
                    .font(.title2)
                    .symbolEffect(.bounce.down.byLayer, value: animatedTab.isAnimating)
                Text(tab.title)
                    .font(.caption2)
                    .textScale(.secondary)
            }
            .frame(maxWidth: .infinity)
            .foregroundStyle(activeTab == tab ? Color.primary: Color.gray.opacity(0.8))
            .padding(.top, 15)
            .padding(.bottom, 10)
            .contentShape(.rect)
            .onTapGesture {
                withAnimation(.bouncy, completionCriteria: .logicallyComplete,  {
                    activeTab = tab
                    animatedTab.isAnimating = true
                }, completion: {
                    var transaction = Transaction()
                    transaction.disablesAnimations = true
                    withTransaction(transaction){
                        animatedTab.isAnimating = nil
                    }
                })
            }
            .background(.bar)
        }
    }
}

タブのアニメーション

Image(systemName:): タブのアイコンを表示する部分です。systemName は、SF Symbols の名前を指定することで、アイコンを呼び出します。
.symbolEffect(.bounce.down.byLayer): ここで、bounce.down というアニメーションを指定しています。これにより、タブが押されたときに「バウンド」する動きが発生します。

タブの選択とアニメーションの状態変更

.onTapGesture: 各タブがタップされたときの処理です。withAnimation ブロック内でタブの選択をアニメーション付きで変更しています。アニメーションが完了すると、animatedTab.isAnimating の値をクリアし、アニメーションの状態をリセットします。

setUpTab モディファイア

setUpTab という独自のモディファイアを使って、タブの設定を一箇所にまとめています。

extension View {
    @ViewBuilder
    func setUpTab(_ tab: Tab) -> some View {
        self
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .tag(tab)
            .toolbar(.hidden, for: .tabBar)
    }
}

これにより、各タブのレイアウトやタブの選択状態を一貫して管理でき、コードの可読性と再利用性が向上しています。

まとめ

今回の記事では、SwiftUIでタブに動きをつける方法について解説しました。タブのアイコンやテキストにアニメーションを追加することで、視覚的なフィードバックを強化し、ユーザー体験を向上させることができます。

Discussion