SwiftUI:创建新增项时背景垂直下移的自定义动态列表


我已通过名为VectorShape的Shape结构体创建背景,并编写path方法绘制该形状,代码如下:
import SwiftUI struct VectorShape: Shape { func path(in rect: CGRect) -> Path { var path = Path() let width = rect.size.width let height = rect.size.height path.move(to: CGPoint(x: 0.083771389*width, y: 0.0048507464*height)) path.addLine(to: CGPoint(x: 0.0625162683*width, y: 0.0048507464*height)) path.addCurve(to: CGPoint(x: 0.0579251837*width, y: 0.0703358247*height), control1: CGPoint(x: 0.0548233261*width, y: 0.0097014928*height), control2: CGPoint(x: 0.058639587*width, y: 0.0562963474*height)) path.addCurve(to: CGPoint(x: 0.0625162683*width, y: 0.7512437811*height), control1: CGPoint(x: 0.0565676091*width, y: 0.0970149301*height), control2: CGPoint(x: 0.0625162683*width, y: 0.5410447761*height)) path.addLine(to: CGPoint(x: 0, y: 0.7512437811*height)) path.addCurve(to: CGPoint(x: 0.0021402598*width, y: 1.3582089552*height), control1: CGPoint(x: 0, y: 0.7512437811*height), control2: CGPoint(x: 0.0021406803*width, y: 1.1144278607*height)) path.addLine(to: CGPoint(x: 0.083771389*width, y: 1.3582089552*height)) path.addLine(to: CGPoint(x: 0.7362637363*width, y: 1.3582089552*height)) path.addLine(to: CGPoint(x: 0.7362637363*width, y: 0)) path.addLine(to: CGPoint(x: 0.083771389*width, y: 0.0048507464*height)) path.closeSubpath() return path } } #Preview{ VectorShape().fill().frame(width: 273, height: 201) }
目前我存在以下疑问:
- 如何在
VectorShape内部创建可动态变化的列表,使得新增列表项时VectorShape背景可垂直向下移动
我曾尝试使用ZStack,在其中添加VectorShape和用于列表的VStack,但列表无法被VectorShape包含。因此我不清楚如何实现列表动态化,让VectorShape背景随新增列表项垂直下移,是否需要借助其他软件完成动态部分?
以下是我已完成的结构代码:
import SwiftUI struct ChecklistItem: Identifiable { var id = UUID() var title: String var isChecked: Bool } struct ChecklistTest: View { @State private var checklistItems = [ ChecklistItem(title: "Item 1", isChecked: false), ChecklistItem(title: "Item 2", isChecked: false), ChecklistItem(title: "Item 3", isChecked: false) ] var body: some View { ZStack{ VectorShape() .fill(Color(#colorLiteral(red: 1, green: 0.96009022, blue: 0.8565915227, alpha: 1))) .stroke(.black) .frame(width: 300, height: 300) VStack { ForEach($checklistItems) { $item in HStack { Text(item.title) Spacer() Image(systemName: item.isChecked ? "checkmark.square" : "square") .onTapGesture { item.isChecked.toggle() } } .padding(5) if item.id != checklistItems.last?.id { Divider() .overlay(.black) } } } .frame(width: 280, height: 150, alignment: .leading) .padding(.top, 60) } } } #Preview { ChecklistTest() }
解决方案
核心思路是让VectorShape作为列表容器的背景,而非独立的ZStack层,这样形状会自动跟随列表高度动态变化。修改后的完整代码如下:
import SwiftUI struct ChecklistItem: Identifiable { var id = UUID() var title: String var isChecked: Bool } struct ChecklistTest: View { @State private var checklistItems = [ ChecklistItem(title: "Item 1", isChecked: false), ChecklistItem(title: "Item 2", isChecked: false), ChecklistItem(title: "Item 3", isChecked: false) ] @State private var newItemTitle = "" var body: some View { VStack(spacing: 16) { // 带VectorShape背景的列表容器 VStack { ForEach($checklistItems) { $item in HStack { Text(item.title) Spacer() Image(systemName: item.isChecked ? "checkmark.square" : "square") .onTapGesture { item.isChecked.toggle() } } .padding(5) if item.id != checklistItems.last?.id { Divider() .overlay(.black) } } } .padding(.top, 60) // 适配形状顶部的空白区域 .padding(.bottom, 40) // 适配形状底部的延伸区域 .padding(.horizontal, 20) .background( VectorShape() .fill(Color(#colorLiteral(red: 1, green: 0.96009022, blue: 0.8565915227, alpha: 1))) .stroke(.black) ) .frame(width: 300) // 固定宽度,高度随列表内容自动调整 // 新增列表项的输入框和按钮 HStack { TextField("输入新项", text: $newItemTitle) .textFieldStyle(.roundedBorder) Button("添加") { guard !newItemTitle.isEmpty else { return } checklistItems.append(ChecklistItem(title: newItemTitle, isChecked: false)) newItemTitle = "" } .buttonStyle(.borderedProminent) } .padding(.horizontal, 20) } .padding() } } #Preview { ChecklistTest() }
关键修改说明
- 背景绑定:将
VectorShape设置为列表容器的background,而非ZStack的独立层,这样形状会完全贴合容器的尺寸,列表高度变化时形状自动跟随。 - 移除固定高度:删掉了原代码中
VectorShape的固定frame(height: 300),让它根据内容高度自适应。 - 适配内边距:调整列表的
padding值,让内容和形状的轮廓对齐,避免内容超出形状范围。 - 新增功能:添加了输入框和按钮,方便测试新增列表项时的动态效果。
由于你的VectorShape是基于宽高比例绘制的路径,无论容器高度如何变化,形状的轮廓都会按比例缩放,完全满足新增列表项时背景垂直下移的需求,不需要额外软件辅助。
内容的提问来源于stack exchange,提问作者DarthKibo
相关产品推荐
相关产品推荐

