🔥

[SwiftUI]TabViewをボタンアクションでアニメーション付きで変える

2023/10/16に公開

今回はSwiftUIでTabViewを使い、UIKitのUIPageViewControllerのようなページ遷移実装します。

やりたいこと

  • TabViewを使用してページ遷移を実装する
  • スワイプでページ遷移ができる
  • ボタンアクションなどでアニメーション付きのページ遷移ができる

特に、最後の「プログラムでアニメーション付きページ遷移をする」ところができるように実装します。

環境

  • Xcode: 14.3
  • iOS: 16.4

実装

TabViewでページ遷移するようにする

スワイプ操作でTabViewでページ遷移するように実装します。


@State var currentTab: Int = 0

TabView(selection: $currentTab) {
	PageView(index: 1).tag(0)
	PageView(index: 2).tag(1)
	PageView(index: 3).tag(2)
}
.tabViewStyle(.page(indexDisplayMode: .never))

.tabViewStyle.page(indexDisplayMode: .never)を設定することで、ページ遷移の挙動になります。さらにindexDisplayModeつまり下部に表示される現在のページを表すドットの表示について.neverを設定することで非表示としています。
TabView.selectionの説明については割愛します。
.pageはiOS14から使用できます。

https://developer.apple.com/documentation/swiftui/pagetabviewstyle
https://developer.apple.com/documentation/swiftui/tabviewstyle/page(indexdisplaymode:)

@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *)
@available(macOS, unavailable)
extension TabViewStyle where Self == PageTabViewStyle {
    public static var page: PageTabViewStyle { get }
    public static func page(indexDisplayMode: PageTabViewStyle.IndexDisplayMode) -> PageTabViewStyle
}

現状では、プログラム的にページを変えるためにcurrentTabを変更しても、ページは瞬時に変わります。

ページ遷移時にアニメーションを追加する

通常のスワイプでページを変更すると、当然アニメーションでのページ遷移となります。
ボタンアクションなどでプログラム的にアニメーション付きでページを変えるためには、以下の実装が必要になります。

TabView(selection: $currentTab) {
	PageView(index: 1).tag(0)
	PageView(index: 2).tag(1)
	PageView(index: 3).tag(2)
}
.tabViewStyle(.page(indexDisplayMode: .never))
.animation(.easeInOut, value: currentTab)

.animation(_:value:)を使用することで、valueに設定した値の変更を検知してアニメーションをします。

https://developer.apple.com/documentation/swiftui/view/animation(_:value:)

これでプログラム的なページ変更でもアニメーションするようになりました。

最終的な実装

struct ContentView: View {
    
    @State var currentTab: Int = 0

    var body: some View {
        VStack {
            
            TabView(selection: $currentTab) {
                PageView(index: 1).tag(0)
                PageView(index: 2).tag(1)
                PageView(index: 3).tag(2)
            }
            .frame(maxHeight: .infinity)
            .tabViewStyle(.page(indexDisplayMode: .never))
            .animation(.easeInOut, value: currentTab)
            
            HStack(spacing: 32) {
                Button("Page.1") {
                    currentTab = 0
                }
                .padding()
                Button("Page.2") {
                    currentTab = 1
                }
                .padding()
                Button("Page.3") {
                    currentTab = 2
                }
                .padding()
            }
            
        }
        .padding()
    }

}

このようなアニメーションになります。
Screen Record

ソースコード

ソースコードはこちらに置きました。
https://github.com/usk-sample/TabViewSample-iOS

参考

SwiftUIのTabViewでボタンアクションによるスライド切り替え|TAAT
Animate transition between views o… | Apple Developer Forums

Discussion