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

SwiftUI HStack/VStack嵌套实现快餐APP菜单布局对齐求解

SwiftUI 快餐类APP菜单布局对齐修复方案

核心调整逻辑

完全保留菜单项外层HStack横向容器的结构,仅调整内部层级即可实现标题、套餐标识、价格的纵向排布,不需要提前掌握List/集合视图的数据绑定方法,适配入门阶段学习节奏:

  • 移除菜单项容器上错误添加的.fixedSize()修饰符,该修饰符会强制容器贴合内容尺寸引发布局错位、内容超出屏幕
  • 单个菜单项HStack内部固定为三层结构:左侧餐品图片 → 中间纵向文本容器 → 右侧占位Spacer
  • 把餐品名称、套餐标识、价格全部放入图片右侧的VStack容器,自然实现纵向排布
  • 给餐品图片设置固定尺寸,避免图片原始尺寸过大撑乱布局

可直接替换的实现代码

基础结构修复说明

原代码顶部头部区和ScrollView没有放在统一根容器下,会引发布局超出屏幕问题,以下是完整可运行的调整后代码:

import SwiftUI

// 你预先定义的MenuItem模型保留即可
struct MenuItem {
  let name:String
  let description:String
  let imageUrl :String
  let caroloriesK:Decimal
  let caroloriesJ:Decimal
  let price :Decimal
  let mealprice:Decimal
}

struct ContentView: View {
    // 入门阶段可以先手动创建菜单项实例,不需要强制上列表绑定
    let menuItems: [MenuItem] = [
        MenuItem(
            name: "Big Mac",
            description: "",
            imageUrl: "bigmac",
            caroloriesK: 550,
            caroloriesJ: 2301,
            price: 3.99,
            mealprice: 5.00
        ),
        MenuItem(
            name: "Chicken Sandwich",
            description: "",
            imageUrl: "chickensandwhich",
            caroloriesK: 480,
            caroloriesJ: 2008,
            price: 3.49,
            mealprice: 4.79
        ),
        MenuItem(
            name: "Double Quarter Pounder with Cheese",
            description: "",
            imageUrl: "doubleqpwithchees",
            caroloriesK: 740,
            caroloriesJ: 3096,
            price: 4.99,
            mealprice: 6.29
        )
    ]
    
    var body: some View {
        // 根VStack包裹所有页面内容
        VStack {
            // 顶部头部区
            VStack(spacing: 8) {
                Image("logo")
                    .resizable()
                    .scaledToFit()
                    .frame(height: 60)
                Text("Choose Your Best Meal")
                    .font(.title)
                    .fontWeight(.bold)
                Text("Mcdolands")
                    .foregroundColor(.secondary)
                    .padding(.bottom)
            }
            
            ScrollView(.vertical, showsIndicators: false) {
                // 顶部分类按钮栏
                HStack(spacing: 12) {
                    Button(action: {
                        print("Menu tapped")
                    }) {
                        Text("Menu")
                            .frame(minWidth: 0, maxWidth: .infinity)
                            .font(.system(size: 18, weight: .semibold))
                            .padding(.vertical, 12)
                            .foregroundColor(.white)
                            .overlay(
                                RoundedRectangle(cornerRadius: 8)
                                    .stroke(Color.white, lineWidth: 2)
                            )
                    }
                    .background(Color.yellow)
                    .cornerRadius(8)
                    
                    Button(action: {
                        print("Offer tapped")
                    }) {
                        Text("Offer")
                            .frame(minWidth: 0, maxWidth: .infinity)
                            .font(.system(size: 18))
                            .padding(.vertical, 12)
                            .foregroundColor(.white)
                    }
                    .background(Color.yellow)
                    .cornerRadius(8)
                    
                    Button(action: {
                        print("Offer tapped")
                    }) {
                        Text("Offer")
                            .frame(minWidth: 0, maxWidth: .infinity)
                            .font(.system(size: 18))
                            .padding(.vertical, 12)
                            .foregroundColor(.white)
                    }
                    .background(Color.yellow)
                    .cornerRadius(8)
                    
                    Button(action: {
                        print("Offer tapped")
                    }) {
                        Text("Offer")
                            .frame(minWidth: 0, maxWidth: .infinity)
                            .font(.system(size: 18))
                            .padding(.vertical, 12)
                            .foregroundColor(.white)
                    }
                    .background(Color.yellow)
                    .cornerRadius(8)
                }
                .padding(.horizontal)
                
                // 菜单项列表区 单个菜单项外层保留HStack结构
                VStack(spacing: 20) {
                    // Big Mac菜单项
                    HStack(alignment: .top, spacing: 12) {
                        Image(menuItems[0].imageUrl)
                            .resizable()
                            .scaledToFit()
                            .frame(width: 90, height: 90)
                        
                        // 所有文本内容放入VStack实现纵向排布
                        VStack(alignment: .leading, spacing: 6) {
                            Text(menuItems[0].name)
                                .font(.headline)
                                .fontWeight(.bold)
                            
                            Text("Meal")
                                .font(.subheadline)
                                .foregroundColor(.secondary)
                                .padding(.horizontal, 8)
                                .padding(.vertical, 2)
                                .background(Color.yellow.opacity(0.2))
                                .cornerRadius(4)
                            
                            Text("£\(menuItems[0].mealprice)")
                                .font(.subheadline)
                                .fontWeight(.semibold)
                                .foregroundColor(.red)
                        }
                        .padding(.top, 8)
                        
                        Spacer()
                    }
                    .padding(.horizontal)
                    .padding(.vertical, 8)
                    .background(Color(.systemGray6))
                    .cornerRadius(12)
                    
                    // 鸡肉堡菜单项
                    HStack(alignment: .top, spacing: 12) {
                        Image(menuItems[1].imageUrl)
                            .resizable()
                            .scaledToFit()
                            .frame(width: 90, height: 90)
                        
                        VStack(alignment: .leading, spacing: 6) {
                            Text(menuItems[1].name)
                                .font(.headline)
                                .fontWeight(.bold)
                            
                            Text("Meal")
                                .font(.subheadline)
                                .foregroundColor(.secondary)
                                .padding(.horizontal, 8)
                                .padding(.vertical, 2)
                                .background(Color.yellow.opacity(0.2))
                                .cornerRadius(4)
                            
                            Text("£\(menuItems[1].mealprice)")
                                .font(.subheadline)
                                .fontWeight(.semibold)
                                .foregroundColor(.red)
                        }
                        .padding(.top, 8)
                        
                        Spacer()
                    }
                    .padding(.horizontal)
                    .padding(.vertical, 8)
                    .background(Color(.systemGray6))
                    .cornerRadius(12)
                    
                    // 双层芝士堡菜单项
                    HStack(alignment: .top, spacing: 12) {
                        Image(menuItems[2].imageUrl)
                            .resizable()
                            .scaledToFit()
                            .frame(width: 90, height: 90)
                        
                        VStack(alignment: .leading, spacing: 6) {
                            Text(menuItems[2].name)
                                .font(.headline)
                                .fontWeight(.bold)
                            
                            Text("Meal")
                                .font(.subheadline)
                                .foregroundColor(.secondary)
                                .padding(.horizontal, 8)
                                .padding(.vertical, 2)
                                .background(Color.yellow.opacity(0.2))
                                .cornerRadius(4)
                            
                            Text("£\(menuItems[2].mealprice)")
                                .font(.subheadline)
                                .fontWeight(.semibold)
                                .foregroundColor(.red)
                        }
                        .padding(.top, 8)
                        
                        Spacer()
                    }
                    .padding(.horizontal)
                    .padding(.vertical, 8)
                    .background(Color(.systemGray6))
                    .cornerRadius(12)
                }
                .padding(.top, 20)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

入门阶段适配提示

  • 现阶段不需要强行学习ForEach/List数据绑定,手动写HStack菜单项、直接调用提前创建的MenuItem实例属性即可,等对VStack/HStack布局逻辑熟悉后,再学习列表循环渲染的方法
  • 所有间距、字号、颜色都可以根据目标截图调整,核心布局逻辑不需要改动
  • 如果需要调整纵向排布的内容间距,只需要修改文本VStack的spacing参数即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:51:28