TabView, TabItem: запуск кода при выборе или добавлении онтологии

#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 для TabItem

2. Спасибо! Я получаю несколько инструкций печати со следующим: 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 */
 }