Reputation: 2883
I am working with TabView and would like to add more data when a user clicks for the 2nd time on the same tab item . I have been looking at other examples such as this SwiftUI TabView On Click Action however I have not been able to get it to work . I have a simple example below (full code) . Basically if the tag is already on MainView and the user clicks it again I want to hit the print("Update get more data") code . I have used the OnReceive method however that does not work if clicked more than 1 time in the same tab . I have also tried to use onTapGesture outside of the TabView but do not seem to bind any suggestions would be great since I am learning SwiftUI and I am using version 3.0
*TabView(selection: $selectedTab) {
...
}.onTapGesture {
print(selectedTab) // This always give MainView
}*
I have also tried the above and it is always giving MainView
import SwiftUI
import Combine
struct TabViews: View {
@State var selectedTab: Tab = .MainView
@State private var firstPass = false
var body: some View {
TabView(selection: $selectedTab) {
Text("Main View")
.padding()
.tabItem {
Image(systemName: "1.circle")
Text("First")
}
.tag(Tab.MainView)
Text("Menu View")
.padding()
.tabItem {
Image(systemName: "2.circle")
Text("Second")
}
.tag(Tab.MenuView)
}
.onReceive(Just(selectedTab)) {
print("Tapped!! \(selectedTab)")
if $0 == .MainView {
if firstPass == true {
// update list
print("Update get more data")
}
firstPass = true
}
if $0 == .MenuView {
print("2")
}
}
}
}
extension TabViews {
enum Tab: Hashable {
case MainView
case MenuView
case RankingView
}
}
struct TabView_Previews: PreviewProvider {
static var previews: some View {
TabViews()
}
}
Upvotes: 1
Views: 451
Reputation: 63667
Publish your tab variable
@Published var tabSelection: Tab = .mainView
Then catch the change in your TabView using Combine’s onReceive
. This will trigger, even when re-selecting the tab.
import Combine
...
.onReceive(appModel.$tabSelection) { newSelection in
// ... do anything
// avoid infinite loop
if tabSelected != newSelection {
self.tabSelected = newSelection
}
}
I placed onReceive on a NavigationStack of a TabView child view, in order to reset the navigation stack
Passing a function as a Binding also works, but semantically, you are not really Binding.
Upvotes: 0
Reputation: 257543
For your scenario the solution is to use proxy binding (to intercept every click) as was shown in second link from referenced question.
Tested with Xcode 13 / iOS 15
struct TabViews: View {
@State var selectedTab: Tab = .MainView
@State private var firstPass = false
private var selection: Binding<Tab> { Binding( // << this !!
get: { selectedTab },
set: {
selectedTab = $0
print("Tapped!! \(selectedTab)")
if $0 == .MainView {
if firstPass == true {
// update list
print("Update get more data")
firstPass = false // << reset !!
return
}
firstPass = true
}
if $0 == .MenuView {
print("2")
firstPass = false
}
}
)}
var body: some View {
TabView(selection: selection) { // << here !!
Text("Main View")
.padding()
.tabItem {
Image(systemName: "1.circle")
Text("First")
}
.tag(Tab.MainView)
Text("Menu View")
.padding()
.tabItem {
Image(systemName: "2.circle")
Text("Second")
}
.tag(Tab.MenuView)
}
}
}
Upvotes: 2