我有一个带有三个 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 上的停止按钮一样。
非常感谢任何帮助!
使用
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"
}
}
}
}
我唯一能想到的就是当满足您所需的条件时选择所需的选项卡。像这样的东西:
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)
}
}
}
我想我实际上找到了一个潜在的解决方案。我认为这对我有用。我将条件 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)
}
}
起初我使用的是 Steven-Carrot 的方法,该方法使用
onChange
来 恢复 selectedIndex。 叹息:恢复意味着视图实际上发生了变化,但恢复速度太快以至于不可见。然而onAppear实际上是被触发的。这会导致一些逻辑问题,但可以通过一些标志来解决。
真正的问题是在iOS16中当真正更改为其他视图时。然后在新视图上不再调用
onAppear
。那是最后一滴水洒了我的玻璃,所以我决定创建一个强大的 UIKit 包装器:
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)
}
}