You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中实现提醒App新建提醒表单的底部弹出卡片组件是什么?

实现从底部弹出的可滑动关闭覆盖卡片

SwiftUI没有直接对应这种“底部弹出卡片”的内置组件,但可以通过两种方案快速实现你要的效果:

方案一:iOS 15+ 用系统Sheet自定义配置

从iOS15开始,系统Sheet支持自定义弹出高度和拖动指示器,自带滑动关闭逻辑,是最省心的方案:

struct ContentView: View {
    @State private var isSheetShown = false
    
    var body: some View {
        Button("打开表单") {
            isSheetShown = true
        }
        .sheet(isPresented: $isSheetShown) {
            // 这里放你的表单内容
            Form {
                TextField("输入名称", text: .constant(""))
                Toggle("开启选项", isOn: .constant(false))
                Button("提交") {
                    isSheetShown = false
                }
            }
            .presentationDetents([.medium, .large]) // 设置可停留的高度(中等/全屏)
            .presentationDragIndicator(.visible) // 显示顶部拖动条
        }
    }
}
  • presentationDetents:控制卡片的弹出高度,.medium对应约一半屏幕高度,.large是全屏
  • presentationDragIndicator:显示顶部的拖动指示器,用户可拖动它调整高度或直接滑走关闭

方案二:自定义底部卡片(兼容iOS 15以下)

如果需要支持更早iOS版本,可通过手势+动画封装自定义组件:

struct CustomBottomCard<Content: View>: View {
    @Binding var isPresented: Bool
    let content: Content
    @State private var dragOffset = CGSize.zero
    
    init(isPresented: Binding<Bool>, @ViewBuilder content: () -> Content) {
        self._isPresented = isPresented
        self.content = content()
    }
    
    var body: some View {
        ZStack(alignment: .bottom) {
            if isPresented {
                // 背景遮罩,点击可关闭
                Color.black.opacity(0.3)
                    .ignoresSafeArea()
                    .onTapGesture {
                        isPresented = false
                    }
                
                // 卡片主体
                VStack(spacing: 0) {
                    // 顶部拖动条
                    Rectangle()
                        .frame(width: 40, height: 6)
                        .cornerRadius(3)
                        .foregroundColor(.gray)
                        .padding(.top, 10)
                    
                    content
                }
                .background(Color.white)
                .cornerRadius(16, corners: [.topLeft, .topRight])
                .offset(y: dragOffset.height)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            if value.translation.height > 0 { // 仅允许向下拖动
                                dragOffset = value.translation
                            }
                        }
                        .onEnded { value in
                            if value.translation.height > 100 { // 拖动距离超过阈值则关闭
                                isPresented = false
                            }
                            dragOffset = .zero
                        }
                )
                .transition(.move(edge: .bottom))
                .animation(.spring(), value: isPresented)
            }
        }
    }
}

// 使用示例
struct ContentView: View {
    @State private var isCardShown = false
    
    var body: some View {
        Button("打开自定义卡片") {
            isCardShown = true
        }
        .overlay(
            CustomBottomCard(isPresented: $isCardShown) {
                Form {
                    TextField("用户名", text: .constant(""))
                    SecureField("密码", text: .constant(""))
                    Button("登录") {
                        isCardShown = false
                    }
                }
                .frame(height: 300)
            }
        )
    }
}
  • 自定义组件通过ZStack在页面底部叠加卡片,背景遮罩点击可快速关闭
  • 利用DragGesture监听拖动动作,达到设定阈值时触发关闭逻辑,配合过渡动画实现弹出/关闭效果

核心说明

SwiftUI没有直接命名为“覆盖卡片”的内置组件,但上述两种方案完全可以实现你要的需求:

  • iOS15及以上优先用系统Sheet的自定义配置,体验和系统原生一致,无需额外封装
  • 低版本则需要自己封装组件,核心是手势监听+动画过渡的组合使用

内容的提问来源于stack exchange,提问作者Chip Bell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:42:18