#swift #swiftui #tabview #tabitem
#swift #swiftui #tabview #tabitem
Вопрос:
Я хотел бы запустить некоторый код, когда выбрана одна из моих вкладок в tabview.
Гипотетически: я хочу создать приложение с намерением: А) использовать tabview и Б) серьезно запутать пользователя. Для достижения этой цели я создам приложение с вкладками «один», «два» и «три» и представлениями «один», «два» и «три». Затем, когда будет выбрана вторая вкладка, я изменю вид «два», чтобы вместо этого сказать «один». Дьявольский.
Решение здравого смысла для этого выглядит примерно так:
import SwiftUI
struct ContentView: View {
@State private var two : String = "Two"
var body: some View {
TabView() {
Text("One")
.tabItem {
Text("One")
}
Text("Two")
.tabItem {
Text(two)
}
.onTapGesture {
print("Tapped!!")
self.two = "One"
}
Text("Three")
.tabItem {
Text("Three")
}
}
}
}
К сожалению, это работает точно так же, как обычное приложение, и не сбивает пользователя с толку, потому что two не обновляется (и в консоли нет «Tapped!»).
Как я могу запускать код при выборе или нажатии TabItem? Это может быть обновление переменных, запуск анимации или что-то еще.
Ответ №1:
Вот решение — вы можете наблюдать за изменением выбора вкладки и реагировать соответствующим образом.
Протестировано с Xcode 12 / iOS 14
import Combine // << needed for Just publisher below
struct ContentView: View {
@State private var two : String = "Two"
@State private var selection: Int = 1
var body: some View {
TabView(selection: $selection) {
Text("One")
.tabItem {
Text("One")
}.tag(1)
Text("Two")
.tabItem {
Text(two)
}.tag(2)
Text("Three")
.tabItem {
Text("Three")
}.tag(3)
}
// .onChange(selection) { // << if SwiftUI 2.0 min spec
.onReceive(Just(selection)) {
print("Tapped!!")
if $0 == 2 {
self.two = "One"
}
}
}
}
Комментарии:
1. Как считать с
.onTapGesture
для TabItem2. Спасибо! Я получаю несколько инструкций печати со следующим:
LazyHStack { TabView(selection: $annotationIndex) { ForEach(filteredListings.indices, id: .self) { index in Text("FOO") } } .onReceive(Just(annotationIndex)) { index in print("select (index)") } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) }
3. Это кажется правильным подходом, но я не могу заставить его работать на меня. «Tapped» печатается один раз при загрузке представления, но не повторно при смене вкладок
Ответ №2:
Вместо использования onTapGesture в TabView мы можем написать расширение для привязки, и оно обнаружит новое значение выбора вкладки, даже если мы нажмем на панель вкладок на той же вкладке, оно обнаружит изменения. Здесь мне предоставляется расширение привязки.
extension Binding {
func onUpdate(_ closure: @escaping () -> Void) -> Binding<Value> {
Binding(get: {
wrappedValue
}, set: { newValue in
wrappedValue = newValue
closure()
})
}}
Я использовал это в своем TabView. Я прикрепил свой код ниже.
TabView(selection: $tabSelection.onUpdate {
setNewValue(value: tabSelection)
}) {
ContentView()
.tabItem {
Label {
Text("Home")
} icon: {
Image("HomePage_icon")
.renderingMode(.template)
}
}
.tag(TabViews.homepage)
}
Функция SetNewValue, эта функция действует как onTapGesture
func setNewValue(value: TabViews){
self.tabSelection = value
/* inside this function we can write the code, we like to write it in onTapGesture */
}