今回はTabView
にButton
を埋め込みたいと思ったのですが、埋め込めれそうになかった為、代替方法を試してみることにしました。
環境
- Xcode 14.2
- iOS 16.1
はじめに
Button
をViewの下部に埋め込む方法としては、toolBar
を使用する方法がありますが、
struct ContentView: View {
var body: some View {
NavigationStack {
TabView {
Text("List")
.tabItem {
Label("List",
systemImage: "list.bullet.rectangle")
}
Text("Favorite")
.tabItem {
Label("Favorite",
systemImage: "star")
}
}
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button {
print("Add")
} label: {
Image(systemName: "plus")
}
}
}
}
}
}
この方法だと、TabView
がある場合は、その下にToolbarItem
が表示されて、とても気持ち悪い感じになってしまいました。
また、TabView
内にButton
を設置してもtoolbar
のようには機能してくれません。このButton
で行いたいアクションをTabView
内のコンポーネントが選択された時に実行出来れば問題は解決出来そうです。
選択されているTabを監視する
どのTabが選択されているか監視出来る様にSelection
を追加します。
struct ContentView: View {
enum Selection {
case list
case favorite
case addItem
}
@State private var selection: Selection = .list
var body: some View {
TabView(selection: $selection) {
Text("List")
.tabItem {
Label("List",
systemImage: "list.bullet.rectangle")
}
.tag(Selection.list)
Text("Favorite")
.tabItem {
Label("Favorite",
systemImage: "star")
}
.tag(Selection.favorite)
Text("AddButton")
.tabItem {
Image(systemName: "plus")
}
.tag(Selection.addItem)
}
}
}
これで、どのTabが選択されているかはselection
の値で監視が出来るようになりました。ただ、まだ監視が出来るだけで、AddButton
のTabを選択すると、AddButtonと表示されたViewに切り替わってしまいます。
今回は画面が切り替わることなくButton風に選択された時になんらかのアクションを実行したいのでもう少し手を加えていきます。
画面が切り替わることなく、アクションを実行する
AddButton
が選択された時に画面が切り替わることなく、なんらかのアクションを実行する為には、下記の2点が必要そうです。
AddButton
が選択されても画面が切り替わらないAddButton
が選択された時にアクションを実行する
AddButtonが選択されても画面が切り替わらないようにする
前回のSelection
の値を保持するlastSelection
を追加し、onChange
内で選択されたTabがaddItem
なら前回のSelection
の値を代入するようにしました。
struct ContentView: View {
enum Selection {
case list
case favorite
case addItem
}
@State private var selection: Selection = .list
@State private var lastSelection: Selection = .list
var body: some View {
TabView(selection: $selection) {
Text("List")
.tabItem {
Label("List",
systemImage: "list.bullet.rectangle")
}
.tag(Selection.list)
Text("Favorite")
.tabItem {
Label("Favorite",
systemImage: "star")
}
.tag(Selection.favorite)
Text("AddButton")
.tabItem {
Image(systemName: "plus")
}
.tag(Selection.addItem)
}
.onChange(of: selection) { _ in
switch selection {
case .list, .favorite:
lastSelection = selection
case .addItem:
selection = lastSelection
}
}
}
}
これでAddButton
を押しても、画面が切り替わらなくなりました。
AddButtonが選択された時にアクションを実行する
あとは、onChange
の.addItem
だった時の分岐の中で行いたいアクションを実行するだけです。
.onChange(of: selection) { _ in
switch selection {
case .list, .favorite:
lastSelection = selection
case .addItem:
print("Add Item or Do something")
selection = lastSelection
}
}
これでTabView
内のItemが押された時にボタンのように画面が切り替わることなく何らかのアクションを実行出来るようになりました。
おわりに
結論としては、TabView
にButton
は埋め込み出来ませんでしたが、Button
のように何らかのアクションを実行することが出来ました。
今回はわかりやすくText("AddButton")
としていますが、Text("")
でも機能します。ただ、EmptyView()
だとtabItem
自体が表示されなくなるのでその他のView
を選択する必要があります。
画面下部にフローティングアクションボタンを配置するUIもありますが、もう少しUI的にスッキリさせれないかなと思い、今回この方法を試してみました。
同じような悩みを抱える方の助けになればと思います。