SwiftUI TabView: как определить щелчок по вкладке?
Я хотел бы запускать функцию каждый раз при нажатии на вкладку.
В приведенном ниже коде (используя
onTapGesture
) когда я нажимаю на новую вкладку,
myFunction
вызывается, но вид вкладок не изменяется.
struct DetailView: View {
var model: MyModel
@State var selectedTab = 1
var body: some View {
TabView(selection: $selectedTab) {
Text("Graphs").tabItem{Text("Graphs")}
.tag(1)
Text("Days").tabItem{Text("Days")}
.tag(2)
Text("Summary").tabItem{Text("Summary")}
.tag(3)
}
.onTapGesture {
model.myFunction(item: selectedTab)
}
}
}
Как я могу получить обе вещи:
- обычно отображается tabview
- моя функция вызывается
3 ответа
Начиная с iOS 14 вы можете использовать
onChange
для выполнения кода при изменении переменной состояния. Вы можете заменить жест касания следующим образом:
.onChange(of: selectedTab) { newValue in
model.myFunction(item: newValue)
}
Если вы не хотите ограничиваться iOS 14, вы можете найти дополнительные параметры здесь: Как я могу запустить действие при изменении состояния?
Приведенные выше ответы работают хорошо, за исключением одного условия. Если вы находитесь на той же вкладке, .onChange() не будет вызываться. лучший способ - создать расширение для привязки
extension Binding {
func onUpdate(_ closure: @escaping () -> Void) -> Binding<Value> {
Binding(get: {
wrappedValue
}, set: { newValue in
wrappedValue = newValue
closure()
})
}
использование будет таким
TabView(selection: $selectedTab.onUpdate{ model.myFunction(item: selectedTab) }) {
Text("Graphs").tabItem{Text("Graphs")}
.tag(1)
Text("Days").tabItem{Text("Days")}
.tag(2)
Text("Summary").tabItem{Text("Summary")}
.tag(3)
}
Вот возможный подход. Для TabView это дает то же поведение, что и нажатие на другую вкладку и обратно, поэтому обеспечивает постоянный внешний вид.
Полный код модуля:
import SwiftUI
struct TestPopToRootInTab: View {
@State private var selection = 0
@State private var resetNavigationID = UUID()
var body: some View {
let selectable = Binding( // << proxy binding to catch tab tap
get: { self.selection },
set: { self.selection = $0
// set new ID to recreate NavigationView, so put it
// in root state, same as is on change tab and back
self.resetNavigationID = UUID()
})
return TabView(selection: selectable) {
self.tab1()
.tabItem {
Image(systemName: "1.circle")
}.tag(0)
self.tab2()
.tabItem {
Image(systemName: "2.circle")
}.tag(1)
}
}
private func tab1() -> some View {
NavigationView {
NavigationLink(destination: TabChildView()) {
Text("Tab1 - Initial")
}
}.id(self.resetNavigationID) // << making id modifiable
}
private func tab2() -> some View {
Text("Tab2")
}
}
struct TabChildView: View {
var number = 1
var body: some View {
NavigationLink("Child \(number)",
destination: TabChildView(number: number + 1))
}
}
struct TestPopToRootInTab_Previews: PreviewProvider {
static var previews: some View {
TestPopToRootInTab()
}
}