はじめに
UIKitのTabBarControllerでは、tabItemのタップを処理するdelegateメソッドがあったが、SwiftUIのTabViewでの実装方法を検証した。なお、iOS13+を前提(SwiftUI2.0で追加されたAPIは使わない)とする。
検証環境
- Xcode 12.4
- iOS14.4 / iOS13.5
実装
TabView
import SwiftUI
struct TabBar_View: View {
@State var selection: Int = 0
// タブ内の表示を先頭にスクロールさせるため、インデックスを保持
@State var advViewIndex: Int = 0
var body: some View {
// MARK: TabItemのタップを検知し、メソッドを実行するための変数。TabViewの selection に設定
let selectedTab = Binding<Int>(get: {
self.selection
}, set: {
if $0 == self.selection {
self.scrollToTop()
}
self.selection = $0
})
TabView(selection: selectedTab) {
HT_View()
.tabItem {
Image("Home_Icon")
.renderingMode(.template)
Text("Home")
}
.tag(0)
Adv_View(index: $advViewIndex)
.tabItem {
Image("Event_Icon")
.renderingMode(.template)
Text("Event")
}
.tag(1)
Room_List()
.tabItem {
Image("Room_Icon")
.renderingMode(.template)
Text("Room")
}
.tag(2)
#if DEBUG
Dummy()
.tabItem {
Image(systemName: "gear")
Text("Dummy")
}
.tag(3)
#endif
}.accentColor(Color.primary)
/* MARK: iOS14では、.id を設定すると、NavigationViewを持つ画面に遷移する際にクラッシュ
* 原因不明。HT_ViewもNavigationView を持っていて、起動時にはクラッシュしないが、他のタブに移動後、戻ってくるとクラッシュした
* iOS14+を対象とする場合は、WindowGroup の利用によるリファクタリングも検討する
*/
//.id(selectedTab)
}
// 表示中のタブのTabItemをタップした時にページの先頭に戻る処理
private func scrollToTop() {
if self.selection == 1 {
// アニメーションを設定しないと、いきなり先頭に戻り違和感がある。iOS13ではアニメーションがわかりずらいが、そのままにしている
withAnimation() {
self.advViewIndex = 0
}
}
}
}
参考リンク
Swiftui TabBar: Action for tapping TabItem of currently selected Tab to reset view