我想在每次点击选项卡时运行一个函数。
在下面的代码中(通过使用
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)
}
}
}
我怎样才能同时获得这两件事:
从 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()
}
}
这真的很有帮助。
当用户登录时,会显示视频选项卡的家庭版本,但再次按视频时,用户必须转到该选项卡的视频版本。家庭版的侧边菜单中有导航。
你的代码可以缩短一点,但它的作用就像一个魅力,我感谢你。
struct MainView: View {
@State private var selection = 0
@Binding var shouldShowHome: Bool
@State private var resetNavigationID = UUID()
/** Navigate to tab view **/
func navigate() -> some View {
VStack {
switch selection {
case 0:
FolderVideoView(shouldShowHome: $shouldShowHome).id(self.resetNavigationID)
case 1:
ChatView()
case 2:
DocumentListView()
case 3:
NewsView()
case 4:
EventCalendarView()
default:
EmptyView()
}
}
.onAppear {
print("Navigating to \(selection)")
}
}
var body: some View {
// Proxy binding to catch taps on selected tabs
let selectable = Binding(
get: { self.selection },
set: { self.selection = $0
// If recreating navigation ID, the tab can be relected, see tabContent()
self.resetNavigationID = UUID()
})
TabView(selection: selectable) {
if GlobalData.sharedGlobal.role == "newuser" {
navigate()
.tabItem {
Image("Chat")
}
.badge(chatViewModel.unreadMessagesCount)
.tag(1)
navigate()
.tabItem {
Image("Video")
}
.tag(0)
} else {
navigate()
.tabItem {
Image("Video")
}
.tag(0)
navigate()
.tabItem {
Image("Chat")
}
.badge(chatViewModel.unreadMessagesCount)
.tag(1)
}
navigate()
.tabItem {
Image("Document")
}
.tag(2)
navigate()
.tabItem {
Image("News")
}
.tag(3)
navigate()
.tabItem {
Image("Event")
}
.tag(4)
}
}
}