SwiftUI ScrollView实现一次滚动多项及卡片布局需求
SwiftUI实现指定的卡片组滚动效果
针对需求中的四个要点,我们可以通过卡片分组、精确尺寸计算和自定义滚动分页行为来实现,以下是修改后的完整代码及关键说明:
关键修改点
- 卡片分组处理:将原卡片数组按每2个元素一组拆分,最后一组若为单个元素则单独成组,确保滚动时每次切换一组(2张或1张)。
- 精确尺寸计算:根据15点的间距要求,计算卡片宽度和高度,保证卡片与边缘、卡片间的间距符合要求。
- 滚动分页配置:使用
scrollTargetLayout和.paging滚动行为,让滚动视图按分组单元切换,同时通过组间小间距让下一组卡片露出部分内容。 - 奇数卡片左对齐:最后一组若只有单个卡片,通过
Spacer()实现左对齐效果。
完整代码
struct CardGallery: View { @State var cards: [Int] = [1,2,3,4,5] // 将卡片按每2个一组拆分,处理奇数数量的情况 private var groupedCards: [[Int]] { var groups = [[Int]]() for index in stride(from: 0, to: cards.count, by: 2) { let endIndex = min(index + 2, cards.count) groups.append(Array(cards[index..<endIndex])) } return groups } var body: some View { GeometryReader { geometry in VStack { let containerWidth = geometry.size.width let containerHeight = geometry.size.height / 1.5 let spacing: CGFloat = 15 // 计算卡片尺寸:左右各15间距,中间15间距,总间距3*15 let cardWidth = (containerWidth - spacing * 3) / 2 // 上下各15垂直间距 let cardHeight = containerHeight - spacing * 2 ZStack { ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: spacing * 0.5) { // 组间小间距,让下一组卡片露出部分 ForEach(groupedCards, id: \.self) { group in HStack(spacing: spacing) { ForEach(group, id: \.self) { level in CardView(level: level) .frame(width: cardWidth, height: cardHeight) } // 最后一组为单个卡片时,添加Spacer实现左对齐 if group.count == 1 { Spacer() } } .frame(width: containerWidth - spacing * 2) // 组宽度适配容器,保证分页切换时占满视图 } } .padding(.horizontal, spacing) // 容器左右15间距 } .scrollTargetLayout() .scrollTargetBehavior(.paging) .background(Color.yellow) .clipShape(RoundedRectangle(cornerRadius: 15)) .overlay( RoundedRectangle(cornerRadius: 15) .strokeBorder(Color.black, lineWidth: 5) ) } .frame(width: containerWidth, height: containerHeight) } .frame(maxWidth: .infinity, maxHeight: .infinity) } .background(Color.green.ignoresSafeArea(.all)) } } struct CardView: View { let level: Int var body: some View { RoundedRectangle(cornerRadius: 15) .fill(Color.blue) .overlay( Text("\(level)") .font(.largeTitle) .foregroundColor(.white) ) // 添加卡片编号便于测试 } }
效果说明
- 初始显示第1、2张卡片,右侧露出第3张的部分内容;
- 滚动后切换到第3、4张卡片,右侧露出第5张的部分内容;
- 再次滚动显示第5张卡片,且卡片左对齐;
- 所有卡片与边缘、卡片间的水平/垂直间距均为15点,两张卡片尺寸均等并占据大部分容器空间。
内容的提问来源于stack exchange,提问作者batman
相关产品推荐
相关产品推荐

