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

SwiftUI中如何使用Button控件实现新增VStack视图的功能

问题原因

你写的代码存在两个核心问题:

  • SwiftUI的Button的action闭包是用来执行业务逻辑的,不能直接返回视图完成渲染,所有要显示的视图都必须写在body的视图树内
  • SwiftUI是状态驱动的视图框架,视图的增减必须通过状态变量的变化来触发
正确实现方案

以下代码完全适配iOS 14 + Xcode 12的运行环境,通过状态变量控制动态视图的生成:

import SwiftUI

struct ContentView: View {
    // 状态变量作为动态视图的数据源,每一项对应一个VStack的内容
    @State private var textList: [String] = []
    
    var body: some View {
        // 外层容器统一放置按钮和动态生成的视图
        VStack(spacing: 16) {
            Button(action: {
                // 点击仅修改数据源,自动触发视图刷新
                textList.append("hello")
            }, label: {
                Image(systemName: "plus.circle.fill")
                    .foregroundColor(.black)
            })
            
            // 遍历数据源生成对应数量的VStack
            ForEach(textList.indices, id: \.self) { index in
                VStack {
                    Text(textList[index])
                }
            }
            
            Spacer()
        }
        .padding()
    }
}
可选优化

如果需要给每个VStack绑定更复杂的自定义属性,可以定义遵循Identifiable协议的结构体简化写法:

// 自定义数据结构
struct CustomItem: Identifiable {
    let id = UUID()
    let content: String
    // 可按需添加更多自定义属性
}

struct ContentView: View {
    // 状态变量改为存储自定义结构体
    @State private var itemList: [CustomItem] = []
    
    var body: some View {
        VStack(spacing: 16) {
            Button(action: {
                itemList.append(CustomItem(content: "hello"))
            }, label: {
                Image(systemName: "plus.circle.fill")
                    .foregroundColor(.black)
            })
            
            // 不需要手动指定id,写法更简洁
            ForEach(itemList) { item in
                VStack {
                    Text(item.content)
                }
            }
            
            Spacer()
        }
        .padding()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 07:18:03