首页 > 解决方案 > 如何在 SwiftUI 中激活动画时挤压胶囊

问题描述

我有一个胶囊可以改变它在屏幕上的位置我想让胶囊在两端被挤压,但是动画不允许我这样做,因为它需要 2 个视图作为开始和结束,我只能管理左右变化的效果,所以挤压效果没有发挥作用的空间!我该怎么做呢?就像苹果做的一样。

在此处输入图像描述

在此处输入图像描述

struct CapsuleView: View {

    @State private var startAnimation: Bool = Bool()

    var body: some View {

        return Capsule()
            .fill(Color.secondary)
            .frame(height: 5, alignment: .center)
            .overlay(Capsule().fill(Color.green).frame(width: 100.0, height: 5, alignment: Alignment.center), alignment: startAnimation ? Alignment.trailing : Alignment.leading)
            .onAppear() { startAnimation.toggle() }
            .animation(Animation.easeInOut(duration: 1.0).repeatForever(autoreverses: true), value: startAnimation)

    }

}

标签: swiftswiftui

解决方案


快速而肮脏的代码,但根据@Zaphod 的建议,尝试使用面具并将你的胶囊放在它后面。然后根据帧大小为偏移设置动画

struct SnakeLoading: View {
    @State
    private var animating: Bool = true
    
    private let height: CGFloat = 10
    private let capsuleWidth: CGFloat = 100
    
    func leadingOffset(size: CGSize) -> CGFloat {
        (-size.width - capsuleWidth) * 0.5 + height
    }
    
    func trailingOffset(size: CGSize) -> CGFloat {
        (size.width + capsuleWidth) * 0.5 - height
    }
    
    var body: some View {
        GeometryReader { geo in
            ZStack {
                // Background
                Rectangle()
                    .fill(Color.gray)
                // Capsule
                Capsule()
                    .fill(Color.green)
                    .offset(x: animating ? leadingOffset(size: geo.size) : trailingOffset(size: geo.size))
                    .frame(width: capsuleWidth, height: height)
                    .onAppear() { animating.toggle() }
                    .animation(Animation.easeInOut(duration: 1.0).repeatForever(autoreverses: true), value: animating)

            }
            .mask(Capsule()
                    .frame(height: height)
            )
        }
        .padding()
    }
}

在此处输入图像描述


推荐阅读