2

I would like to run some code when one of my tabs in tabview is selected.

Hypothetical: I want to create an app with the intentions to: A) Use a tabview and B) seriously confuse the user. To achieve this, I will create an app with tabs "one", "two", and "three", and views "one", "two", and "three". Then, when the second tab is selected, I will change view "two" to say "one" instead. Diabolical.

A common sense solution to this goes something like this:

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")
            }
        }
    }
}

Unfortunately, this works exactly like a normal app and fails to confuse the user because two is not updated (and there is no "Tapped!" in the console).

How can I run code when a tabItem is selected or tapped? This could be updating variables, running an animation, or anything else.

2 Answers 2

12

Here is a solution - you can observe tab selection change and react correspondingly.

Tested with 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"
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

How to count with .onTapGesture for a tabItem
Thanks! I'm getting multiple print statements with the following: 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)) }
This seems like the right approach, but I can't get it to work for me. "Tapped" is printed once when the view loads but not again upon changing tabs
3

Instead of using onTapGesture on tabView we can write an extension to Binding and it will detect the new tab selection value even if we tap the tab bar within the same tab it will detect the changes. Here I am provided the binding extension.

extension Binding {
func onUpdate(_ closure: @escaping () -> Void) -> Binding<Value> {
    Binding(get: {
        wrappedValue
    }, set: { newValue in
        wrappedValue = newValue
        closure()
    })
}}

I used this in my tabView. I attached my code below.

TabView(selection: $tabSelection.onUpdate {
        setNewValue(value: tabSelection)
    }) {
      ContentView()
        .tabItem {
                Label {
                    Text("Home")
                } icon: {
                    Image("HomePage_icon")
                        .renderingMode(.template)
                }
            }
            .tag(TabViews.homepage)
}

SetNewValue function, this function acts like onTapGesture

func setNewValue(value: TabViews){
     self.tabSelection = value
     /* inside this function we can write the code, we like to write it in onTapGesture */
 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.