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

iOS 17 SwiftUI ScrollView:实现堆叠转并排滚动动画

实现从堆叠到并排的滚动平滑过渡动画

我想要实现如下动画效果:视图初始显示时,ScrollView内的视图互相堆叠在后方;当滚动ScrollView时,视图平滑过渡为并排排列。

预期效果

预期动画效果

初始代码

struct ContentView: View {
    
    private let colors: [Color] = [.red, .green, .blue, .yellow, .purple, .black, .brown, .cyan, .gray, .indigo, .orange, .pink, .mint, .teal]
    
    
    var body: some View {
        VStack {
            ScrollView(.horizontal) {
                LazyHStack(spacing: 10.0) {
                    ForEach(colors, id: \.self) { color in
                        RoundedRectangle(cornerRadius: 25.0)
                            .foregroundStyle(color)
                            .containerRelativeFrame(.horizontal)
                            .scrollTransition { content, phase in
                                content
                                    .opacity(phase.isIdentity ? 1: 0.2)
                                    .scaleEffect(y: phase.isIdentity ? 1.0 : 0.8)
                            }
                    }
                }
                .scrollTargetLayout()
            }
            .contentMargins(60.0, for: .scrollContent)
            .scrollTargetBehavior(.viewAligned)
            .scrollIndicators(.hidden)
            .frame(maxHeight: 400.0)
            Spacer()
        }
    }
}

当前初始代码效果

当前代码输出效果

目前我已实现视图并排显示的效果,但无法实现从堆叠状态到并排状态的平滑过渡。

改进后的代码(感谢Mat的帮助)

struct ColorViewModel: Identifiable {
    let id: Int
    let color: Color
}

struct ContentView: View {
    
    private let colors: [ColorViewModel] = [.init(id: 0, color: .red), .init(id: 1, color: .yellow), .init(id: 2, color: .green), .init(id: 03, color: .blue), .init(id: 04, color: .purple), .init(id: 05, color: .pink), .init(id: 06, color: .brown), .init(id: 07, color: .indigo), .init(id: 08, color: .black), .init(id: 09, color: .teal), .init(id: 10, color: .gray), .init(id: 011, color: .white), .init(id: 012, color: .cyan)]

    @State private var hasScrolled: Bool = false
    
    var body: some View {
        
        VStack {
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 10.0) {
                    ForEach(0 ..< colors.count, id: \.self) { number in
                        RoundedRectangle(cornerRadius: 25.0)
                            .frame(maxHeight: 300.0)
                            .containerRelativeFrame(.horizontal)
                            .foregroundStyle(colors[number].color)
                            .if(!hasScrolled) { view in
                                view
                                    .padding(.trailing, colors[number].id == colors.last?.id ? 0 : -220)
                                    .zIndex(CGFloat(-number))
                            }
//                            .scrollTransition { content, phase in
//                                content
//                                    .opacity(phase.isIdentity ? 1 : 0.2)
//                                    .scaleEffect(y: phase.isIdentity ? 1.0 : 0.8)
//                            }
                    }
                }
                .scrollTargetLayout()
            }
            .contentMargins(60.0, for: .scrollContent)
            .scrollTargetBehavior(.viewAligned)
            Spacer()
        }
    }
}

extension View {
    @ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}

当前改进后效果

当前改进后效果

现在需要整合两种状态,实现从堆叠到并排的平滑滚动动画,寻求帮助。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 13:27:52