有没有一种方法可以在 TabView 中禁用 TabItems,类似于 SwiftUI 中按钮上的 .disabled() ?

问题描述 投票:0回答:4

我有一个带有三个 TabItem 的 TabView。当我按下第一个 TabItem 上的按钮时,我想禁用用户点击并转到 TabItem 2 和 TabItem 3 的能力。

我已经使用了disabled(),但我仍然可以点击并转到它们。

TabView(selection: $tabSelected) {
    MeditationTimer(vm: vm)
        .tabItem({
            Label("Meditate", systemImage: "timer")
        })
        .tag(0)
    
    History(vm: vm)
        .tabItem {
            Label("Sessions", systemImage: "list.bullet")
        }
        .tag(1)
        .disabled(vm.isActive)

    Settings(vm: vm)
        .tabItem {
            Label("Settings", systemImage: "gearshape")
        }
        .tag(2)
        .disabled(vm.isActive)
}

将 .disabled() 放在 TabView 本身上实际上是有效的,但是,是的,那么我的整个应用程序中就不再可以点击任何东西了。就像第一个 TabItem 上的停止按钮一样。

非常感谢任何帮助!

swiftui swiftui-tabview
4个回答
1
投票

使用

TabView
selection
onChange

尝试下面的代码,它可能就是您所需要的:

struct ContentView: View {
@State var selection = "A"
@State var isDisable = false
var body: some View {
    TabView(selection: $selection) {
        VStack {
            Button {
                isDisable.toggle()
            } label: {
                Text("View A")
                Text("DISABLE B & C ? = \(String(isDisable))")
                    .foregroundColor(.red)
            }
        }
        .tabItem {
            Image(systemName: "note")
        }
        .tag("A")
        
        Text("View B")
            .tabItem {
                Image(systemName: "note")
            }
            .tag("B")
        
        Text("View C")
            .tabItem {
                Image(systemName: "note")
            }
            .tag("C")
    }
    .onChange(of: selection) { newValue in
        if isDisable {
            selection = "A"
        }
    }
  }
}

0
投票

我唯一能想到的就是当满足您所需的条件时选择所需的选项卡。像这样的东西:

final class ContentViewModel: ObservableObject {
    @Published var selection = 0 {
        didSet {
            if oldValue == 0 && selection != 0 {
                selection = 0
            }
        }
    }
}

struct ContentView: View {
    @StateObject var viewModel = ContentViewModel()

    var body: some View {
        TabView(selection: $viewModel.selection) {
            View1()
                .tabItem {
                    Label("Meditate", systemImage: "timer")
                }
                .tag(0)
            
            View2()
                .tabItem {
                    Label("Sessions", systemImage: "list.bullet")
                }
                .tag(1)

            View3()
                .tabItem {
                    Label("Settings", systemImage: "gearshape")
                }
                .tag(3)
        }
    }
}

0
投票

我想我实际上找到了一个潜在的解决方案。我认为这对我有用。我将条件 TabItem 视图放入 if 语句中。当条件为 true 时,它们会消失,只留下一个选项卡栏来查看所需的单个 TabItem。

TabView(selection: $tabSelected) {
            MeditationTimer(vm: vm, isDisable: $isDisable)
                .tabItem({
                    Label("Meditate", systemImage: "timer")
                })
                .tag(0)
            if !vm.isActive {
                History(vm: vm)
                    .tabItem {
                        Label("Sessions", systemImage: "list.bullet")
                    }
                    .tag(1)
                    
                Settings(vm: vm)
                    .tabItem {
                        Label("Settings", systemImage: "gearshape")
                    }
                    .tag(2)
            }
        }

0
投票

起初我使用的是 Steven-Carrot 的方法,该方法使用

onChange
恢复 selectedIndex。 叹息:恢复意味着视图实际上发生了变化,但恢复速度太快以至于不可见。然而onAppear实际上是被触发的。这会导致一些逻辑问题,但可以通过一些标志来解决。

真正的问题是在iOS16中当真正更改为其他视图时。然后在新视图上不再调用

onAppear
。那是最后一滴水洒了我的玻璃,所以我决定创建一个强大的 UIKit 包装器:

UITabBarController 包装器

struct MyTabView: UIViewControllerRepresentable {
    @Binding var selectedIndex: Int
    @Binding var isTabBarDisabled: Bool
    let viewControllers: [UIViewController]

    class Coordinator: NSObject, UITabBarControllerDelegate {
        var parent: MainTabView

        init(parent: MainTabView) {
            self.parent = parent
        }

        func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
            // See note in updateTabBarEnabled
            if parent.isTabBarDisabled {
                return false
            }
            return true
        }

        func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
            parent.selectedIndex = viewController.tabBarItem.tag
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeUIViewController(context: Context) -> UITabBarController {
        let tabBarController = UITabBarController()
        tabBarController.delegate = context.coordinator
        tabBarController.viewControllers = viewControllers
        updateTabBarEnabled(tabBarController)
        return tabBarController
    }

    func updateUIViewController(_ uiViewController: UITabBarController, context: Context) {
        if uiViewController.selectedIndex != selectedIndex.rawValue {
            uiViewController.selectedIndex = selectedIndex.rawValue
        }
        updateTabBarEnabled(uiViewController)
    }

    private func updateTabBarEnabled(_ tabBarController: UITabBarController) {
        // Note: user interaction becomes disabled so not even the delegate is called.
        // Other approach would be to NOT implement this method and
        // implement only tabBarController(shouldSelect:) method.
        if tabBarController.tabBar.isUserInteractionEnabled != !isTabBarDisabled {
            tabBarController.tabBar.isUserInteractionEnabled = !isTabBarDisabled
        }
    }
}

以及使用它的视图

struct MyOwnView: View {
    @State var tabIndex: Int = 0
    // In my case is disabled at first. Change according to your needs
    @State var isTabBarDisabled: Bool = true

    func makeViewController(view: some View, tabBarIcon: UIImage, tabBarTitle: String, tag: Int) -> UIViewController {
        let vc = UIHostingController(rootView: view)
        vc.tabBarItem = UITabBarItem(title: tabBarTitle, image: tabBarIcon, tag: tag)
        return vc
    }

    var body: some View {
        MyTabView(
            selectedIndex: $tabIndex,
            isTabBarDisabled: $isTabBarDisabled,
            viewControllers: [
                makeViewController(
                    view: View1(), // SwiftUI View
                    tabBarIcon: UIImage(named: "view1Icon"),
                    tabBarTitle: NSLocalizedString("view1", comment: ""),
                    tag: 0),
                makeViewController(
                    view: View2(), // SwiftUI View
                    tabBarIcon: UIImage(named: "view2Icon"),
                    tabBarTitle: NSLocalizedString("view2", comment: ""),
                    tag: 1),
                makeViewController(
                    view: View3(), // SwiftUI View
                    tabBarIcon: UIImage(named: "view3Icon"),
                    tabBarTitle: NSLocalizedString("view3", comment: ""),
                    tag: 3),
            ]
        )
        .ignoresSafeArea(.all)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.