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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:17:02