标签栏上方的底部工作表,如“查找我的应用程序”

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

如何在 SwiftUi 中使 .sheet 呈现在选项卡栏上方而不覆盖它?我见过一种“解决方案”,但在 SwiftUi 中却没有。 enter image description here 到目前为止,我尝试的任何操作都只是将工作表放置在标签栏上

import SwiftUI struct ContentView: View { @State private var showSheet = true var body: some View { TabView { HomeView(showSheet: $showSheet) .tabItem { Label("Home", systemImage: "house") } Text("Second Tab") .tabItem { Label("Second", systemImage: "2.circle") } } } } struct HomeView: View { @Binding var showSheet: Bool var body: some View { VStack { Button("Show TabView Sheet") { showSheet.toggle() } .sheet(isPresented: $showSheet) { SheetContent() .presentationDetents([.medium, .large]) .interactiveDismissDisabled() .presentationBackgroundInteraction(.enabled(upThrough: .large)) } } } } struct SheetContent: View { var body: some View { VStack { Text("First Tab Content") Text("More Content in the Sheet") // Add more content here as needed } } } #Preview { ContentView() }

	
xcode swiftui tabbar bottom-sheet xcode15
1个回答
0
投票
.clear

,然后向工作表内容添加不透明背景。如果您在底部添加一些填充,选项卡按钮将能够显示出来。

但是,当我尝试这样做时,我发现纸张后面的内容被蒙版覆盖,不仅起到调光效果,还阻碍了交互:

Screenshot这意味着,点击选项卡按钮不起作用。

因此,为了使其正常工作,我认为您可能需要使用自定义选项卡栏和自定义工作表。然而,这并不像听起来那么困难:

1。自定义工具栏

为了实现自定义工具栏,使用枚举来定义可用的选项卡类型效果很好:

enum TabType: CaseIterable { case home case second var titleKey: String { "\(self)".capitalized } var symbolName: String { switch self { case .home: "house" case .second: "2.circle" } } }

自定义选项卡栏可以仅使用 
ForEach

来迭代所有枚举类型。通过使用枚举工具,这会变得更容易

CaseIterable
要使标签看起来像原生标签 

TabView

,可以使用自定义

LabelStyle
struct TabLabelStyle: LabelStyle {
    func makeBody(configuration: Configuration) -> some View {
        VStack {
            configuration.icon
            configuration.title
                .font(.caption)
        }
        .frame(maxWidth: .infinity)
    }
}

struct CustomTabBar: View {
    @Binding var selection: TabType

    var body: some View {
        HStack {
            ForEach(TabType.allCases, id: \.self) { type in
                Label(type.titleKey, systemImage: type.symbolName)
                    .labelStyle(TabLabelStyle())
                    .symbolVariant(selection == type ? .fill : .none)
                    .foregroundStyle(selection == type ? Color(.link) : Color(.secondaryLabel))
                    .onTapGesture {
                        withAnimation(.spring(duration: 0.2)) { selection = type }
                    }
            }
        }
        .padding(.vertical)
        .background(.background)
    }
}

要切换所选内容,
ZStack

效果很好。这是更新后的

ContentView
,现在使用
ZStack
+ 自定义 tar 栏作为原生
TabView
的替代品:
struct ContentView: View {
    @State private var showSheet = false
    @State private var selection = TabType.home

    var body: some View {
        VStack(spacing: 0) {
            ZStack {
                switch selection {
                case .home: HomeView(showSheet: $showSheet)
                case .second: Text("Second Tab")
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)

            CustomTabBar(selection: $selection)
        }
    }
}

以这种方式使用自定义标签栏还有其他一些优点:

如果需要,您可以更改选项卡标签的样式
  • 切换内容可以动画化。
2。定制表

自定义工作表可以简单地实现为覆盖层。这在您的情况下特别有效,因为您已禁用交互式关闭并且还希望允许与后台交互。

我假设您希望在切换选项卡时“工作表”消失,因此覆盖层会像以前一样附加到

HomeView

上。我想知道为什么您需要将标志

showSheet
作为对此视图的绑定传递,而不是使其成为
HomeView
中的状态变量,但这样做可以确保从另一个选项卡切换回来时工作表仍然可见.
struct HomeView: View {
    @Binding var showSheet: Bool

    var body: some View {
        VStack {
            Button("Show TabView Sheet") {
                showSheet.toggle()
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .overlay(alignment: .bottom) {
            if showSheet {
                SheetContent()
                    .transition(.move(edge: .bottom))
            }
        }
        .animation(.easeInOut, value: showSheet)
    }
}

struct SheetContent: View {
    var body: some View {
        VStack {
            Text("First Tab Content")
            Text("More Content in the Sheet")
            // Add more content here as needed
        }
        .frame(maxWidth: .infinity, minHeight: 200)
        .background {
            UnevenRoundedRectangle(cornerRadii: .init(topLeading: 20, topTrailing: 20))
                .fill(.yellow)
        }
    }
}

以下是它们如何协同工作:

Animation

© www.soinside.com 2019 - 2024. All rights reserved.