【问题标题】:SwiftUI TabView: how to detect click on a tab?SwiftUI TabView:如何检测标签上的点击?
【发布时间】:2021-02-15 16:40:44
【问题描述】:

我想在每次点击选项卡时运行一个函数。

在下面的代码中(通过使用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)
        }
    }
}

我怎样才能得到这两样东西:

  • tabview 正常显示
  • 我的函数被调用

【问题讨论】:

    标签: swift swiftui tabview swiftui-tabview swiftui-ontapgesture


    【解决方案1】:

    从 iOS 14 开始,您可以使用 onChange 在状态变量更改时执行代码。你可以用这个替换你的点击手势:

            .onChange(of: selectedTab) { newValue in
                model.myFunction(item: newValue)
            }
    

    如果您不想受限于 iOS 14,可以在此处找到其他选项:How can I run an action when a state changes?

    【讨论】:

    • 这仅在选择不同的选项卡时调用该函数,而不是在点击相同的选项卡时调用。
    【解决方案2】:

    这是可能的方法。对于 TabView,它提供与点击另一个选项卡并返回相同的行为,因此具有持久的外观和感觉。

    gif image

    完整模块代码:

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

    【讨论】:

      【解决方案3】:

      除了在一种情况下,上述答案效果很好。如果您出现在同一个选项卡中,则不会调用 .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)
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-22
        • 2021-04-07
        相关资源
        最近更新 更多