SwiftUI ScrollView - iOS 17

问题描述 投票:0回答:1

以下是我想要实现的动画,当视图出现直到滚动视图滚动时,视图一个接一个地堆叠,当它们滚动时,它并排出现。

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()
        }
    }
}

预期输出:

我能够并排获取视图,但如何将视图排列在后面,然后在滚动时平滑地过渡到并排。

这是我的代码输出:

ios swift swiftui scrollview ios17
1个回答
0
投票

为了实现这一点,您可以调整旋转值和项目之间的间距。您可以通过执行以下操作来做到这一点:

struct CoverFlowView<Content: View, Item: RandomAccessCollection>: View where Item.Element: Identifiable {
    
    //MARK: - PROPERTIES
    
    /// Customization
    var itemWidth: CGFloat
    var spacing: CGFloat = .zero
    var rotation: CGFloat = .zero
    
    var items: Item
    var content: (Item.Element) -> Content
    
    var body: some View {
        GeometryReader {
            let size = $0.size
            
            ScrollView(.horizontal, showsIndicators: false) {
                LazyHStack(spacing: 0) {
                    ForEach(items) { item in
                        content(item)
                            .frame(width: itemWidth)
                            .visualEffect { content, geometryProxy in
                                content
                                    .rotation3DEffect(.degrees(rotation(geometryProxy)),
                                                      axis: (x: 0, y: 1, z: 0),
                                                      anchor: .center)
                            }
                            .padding(.trailing, item.id == items.last?.id ? 0 : spacing)
                    } //: LOOP ITEMS
                } //: LAZY HSTACK
                .padding(.horizontal, (size.width - itemWidth) / 2)
                .scrollTargetLayout()
            } //: SCROLL
            .scrollTargetBehavior(.viewAligned)
            .scrollClipDisabled()
            
        } //: GEOMETRY
        
    }
    
    
    //MARK: - Functions
    func rotation(_ proxy: GeometryProxy) -> Double {
        let scrollViewWidth = proxy.bounds(of: .scrollView(axis: .horizontal))?.width ?? 0
        let midX = proxy.frame(in: .scrollView(axis: .horizontal)).midX
        /// Converting into progress
        let progress = midX / scrollViewWidth
        /// Capping progress 0-1
        let cappedProgress = max(min(progress, 1), 0)
        
        /// Limit rotation between 0-90°
        let cappedRotation = max(min(rotation, 90), 0)
        
        let degree = cappedProgress * (cappedRotation * 2)
        
        return cappedRotation - degree
    }
    
}

你这样使用它:

/// State variables
@State private var spacing: CGFloat = 0
@State private var rotation: CGFloat = 0
@State private var mirrorCards = false

CoverFlowView(itemWidth: 250,
                          spacing: spacing,
                          rotation: rotation,
                          items: items) { item in
                RoundedRectangle(cornerRadius: 20)
                    .fill(item.color.gradient)
            }
            .frame(height: 180)
            .rotation3DEffect(
                .degrees(mirrorCards ? 180 : 0),
                axis: (x: 0.0, y: 1.0, z: 0.0)
            )

我在这个简单的例子中使用的项目只是一个具有颜色属性的可识别结构,但您可以使用您真正喜欢的任何东西。 如果您使用大约 -220 的间距并镜像卡片,您可以获得与您正在寻找的结果类似的结果:

让我知道你是如何找到这个解决方案的!

© www.soinside.com 2019 - 2024. All rights reserved.