SwiftUI:如何防止与隐藏的 TabBar 区域交互而不阻塞其他 UI 元素?

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

问题

我在 SwiftUI 中有一个自定义 TabBar,可以用动画显示/隐藏。问题在于隐藏 TabBar 时处理交互:

  1. 我需要防止 TabBar 所在的确切区域发生任何交互(以防止意外点击)
  2. 当我阻止交互时,它会阻止该区域中的所有 UI 元素(例如应该起作用的按钮或其他交互元素)
  3. 在没有阻塞的情况下,用户仍然可以“点击”不可见的TabBar按钮

当前实施情况

这是我的完整代码:

import SwiftUI

struct MainTabView: View {
    @State private var selectedTab = 0
    @State private var tabBarVisible = true
    @State private var tabBarHeight: CGFloat = 0
    
    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .bottom) {
                // Main content
                TabView(selection: $selectedTab) {
                    HomeView()
                        .tag(0)
                    FavoritesView()
                        .tag(1)
                    EmptyView()
                        .tag(2)
                    SettingsView()
                        .tag(3)
                }
                
                // Custom tab bar
                VStack(spacing: 0) {
                    Spacer()
                    if tabBarVisible {
                        CustomTabBar(selectedTab: $selectedTab, tabbarVisible: $tabBarVisible)
                            .padding(.bottom, geometry.safeAreaInsets.bottom)
                            .transition(.move(edge: .bottom))
                            .background(
                                GeometryReader { geo in
                                    Color.clear.onAppear {
                                        tabBarHeight = geo.size.height
                                    }
                                }
                            )
                    }
                }
            }
            .ignoresSafeArea(edges: .bottom)
        }
        .environment(\.tabBarVisibility, $tabBarVisible)
    }
}

struct CustomTabBar: View {
    @Binding var selectedTab: Int
    @Binding var tabbarVisible: Bool
    
    var body: some View {
        HStack(spacing: 0) {
            TabBarButton(imageName: "house", isSelected: selectedTab == 0, action: { selectedTab = 0 })
            TabBarButton(imageName: "magnifyingglass", isSelected: selectedTab == 1, action: { selectedTab = 1 })
            TabBarButton(imageName: "bell", isSelected: selectedTab == 2, action: { selectedTab = 2 })
            TabBarButton(imageName: "person", isSelected: selectedTab == 3, action: { selectedTab = 3 })
        }
        .padding(8)
        .background(
            Color.white
                .shadow(color: Color.black.opacity(0.1), radius: 8, x: 0, y: -4)
        )
        .cornerRadius(25)
        .padding(.horizontal)
    }
}

struct TabBarButton: View {
    let imageName: String
    let isSelected: Bool
    let action: () -> Void
    
    var body: some View {
        Button(action: action) {
            Image(systemName: imageName)
                .font(.system(size: 24))
                .foregroundColor(isSelected ? .white : .black.opacity(0.65))
                .frame(maxWidth: .infinity)
                .padding(.vertical, 10)
                .background(isSelected ? Color.purple.opacity(0.7) : Color.clear)
                .clipShape(Capsule())
        }
    }
}

// Environment key for tab bar visibility
struct TabBarVisibilityKey: EnvironmentKey {
    static let defaultValue: Binding<Bool> = .constant(true)
}

extension EnvironmentValues {
    var tabBarVisibility: Binding<Bool> {
        get { self[TabBarVisibilityKey.self] }
        set { self[TabBarVisibilityKey.self] = newValue }
    }
}

我如何使用它

在内容视图中:

struct ContentView: View {
    var body: some View {
        MainTabView()
    }
}

在其他视图中(隐藏/显示 TabBar 的示例):

struct DetailView: View {
    @Environment(\.tabBarVisibility) var tabBarVisibility
    
    var body: some View {
        ScrollView {
            VStack {
                // Content here
                Button("Toggle TabBar") {
                    withAnimation(.easeInOut) {
                        tabBarVisibility.wrappedValue.toggle()
                    }
                }
            }
        }
        .onAppear {
            // Hide tab bar when view appears
            withAnimation(.easeInOut) {
                tabBarVisibility.wrappedValue = false
            }
        }
        .onDisappear {
            // Show tab bar when view disappears
            withAnimation(.easeInOut) {
                tabBarVisibility.wrappedValue = true
            }
        }
    }
}

期望的行为

  1. 当 TabBar 可见时:

    • 所有按钮均可点击,正常工作
    • 隐藏/显示时动画流畅
    • 带有阴影的白色背景
  2. 当 TabBar 隐藏时:

    • TabBar 所在区域不应响应点击
    • 该区域的其他 UI 元素仍应具有交互性
    • 不应有可见的视觉元素

环境

  • iOS 15+
  • SwiftUI
  • Xcode 14

任何人都可以建议一种方法来实现这一目标吗?我特别需要防止 TabBar 区域在隐藏时与其交互,同时允许其他 UI 元素仍然可以交互。

我尝试过的事情

  1. 使用清晰的矩形来阻止交互:
if !tabBarVisible {
    Rectangle()
        .fill(Color.clear)
        .ignoresSafeArea()
        .contentShape(Rectangle())
        .onTapGesture { }
}

问题:这会阻止该区域的所有交互,包括合法的 UI 元素。

  1. 使用allowsHitTesting:
if !tabBarVisible {
    CustomTabBar(selectedTab: $selectedTab, tabbarVisible: $tabBarVisible)
        .opacity(0)
        .allowsHitTesting(false)
}

问题:这根本不会阻止任何交互。

  1. 使用不可见的占位符:
if !tabBarVisible {
    HStack(spacing: 0) {
        // Same buttons as CustomTabBar but with empty actions
    }
    .opacity(0)
}

问题:仍然允许交互通过。

swift swiftui uitabbar
1个回答
0
投票

我认为即使自定义选项卡栏隐藏也可以更改选项卡的原因是因为 native 选项卡栏仍然存在。您看不到它是因为没有与您的视图关联的

TabItem

因此,要确认问题,请尝试添加一些

TabItem

TabView(selection: $selectedTab) {
    HomeView()
        .tabItem { Text("Home") }
        .tag(0)
    FavoritesView()
        .tabItem { Text("Favourites") }
        .tag(1)
    // ...
}

要隐藏本机选项卡栏,请将

.toolbarVisibility(.hidden, for: .tabBar)
添加到每个子视图(并删除上面添加的
TabItem
):

TabView(selection: $selectedTab) {
    HomeView()
        .toolbarVisibility(.hidden, for: .tabBar)
        .tag(0)
    FavoritesView()
        .toolbarVisibility(.hidden, for: .tabBar)
        .tag(1)
    // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.