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

SwiftUI点击按钮展示自定义高度Bottom Sheet不显示问题求助

自适应高度底部弹框问题修复方案

问题根因

  • 根布局层级错误:SecondView 的body内两个并列视图(按钮、底部弹框组件)没有嵌套在ZStack中,导致底部弹框被渲染在按钮下方不可见
  • 卡片无显隐动画绑定:仅给蒙层添加了透明度绑定,卡片容器没有关联cardShown状态做滑入/滑出控制,点击按钮后卡片没有任何展示变化
  • 缺失卡片基础样式:卡片容器没有设置背景色、边距等样式,即使渲染也会和背景融合无法识别

修复后完整代码

import SwiftUI

struct SecondView: View {
    @State var cardShown = false
    @State var cardDismissal = false
    
    var body: some View {
        // 新增ZStack作为根容器,保证底部弹框渲染在最上层
        ZStack {
            Button {
                cardShown.toggle()
            } label: {
                Text("Show card")
                    .bold()
                    .foregroundColor(Color.white)
                    .background(Color.red)
                    .frame(width: 200, height: 50)
            }
            
            BottomCard(cardShown: $cardShown, cardDismissal: $cardDismissal) {
                CardContent()
            }
        }
    }
}

struct CardContent:View{
    var body: some View{
        // 此处内容可任意修改,卡片高度会自动适配
        Text("自适应高度的底部弹框内容")
            .padding(.vertical, 40)
            .frame(maxWidth: .infinity)
    }
}

struct BottomCard<Content:View>:View{
    @Binding var cardShown:Bool
    @Binding var cardDismissal:Bool
    let content:Content
    
    init(cardShown:Binding<Bool> , cardDismissal:Binding<Bool>, @ViewBuilder content: () -> Content){
        _cardShown = cardShown
        _cardDismissal = cardDismissal
        self.content = content()
    }
    
    var body: some View{
        ZStack{
            // 半透明蒙层
            Color.red.opacity(0.2)
                .opacity(cardShown ? 1 : 0)
                .animation(.easeInOut, value: cardShown)
                .onTapGesture {
                    cardShown.toggle()
                }
                .ignoresSafeArea()
            
            // 卡片容器
            VStack{
                Spacer()
                VStack {
                    content
                }
                .background(Color.white)
                .cornerRadius(12, corners: [.topLeft, .topRight])
                // 卡片滑入滑出逻辑:隐藏时偏移到屏幕外
                .offset(y: cardShown ? 0 : UIScreen.main.bounds.height)
                .animation(.easeInOut, value: cardShown)
            }
            .ignoresSafeArea(.container, edges: .bottom)
        }
    }
}

// 可选扩展:支持指定圆角
extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
        clipShape(RoundedCorner(radius: radius, corners: corners))
    }
}

struct RoundedCorner: Shape {
    var radius: CGFloat = .infinity
    var corners: UIRectCorner = .allCorners

    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        return Path(path.cgPath)
    }
}

自适应高度说明

上述代码没有给卡片设置任何固定高度,高度会完全跟随CardContent的内容自动撑开。如果需要动态调整高度,只需要修改CardContent内部的视图内容(比如切换文本长度、新增/删除控件),卡片会自动重新计算高度并做平滑过渡。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 19:09:01