使用Button触发的动画会停止在Appear中添加的repeatForever动画 [英] Animation triggered using a Button stops a repeatForever animation added onAppear

查看:60
本文介绍了使用Button触发的动画会停止在Appear中添加的repeatForever动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想构建一个进度视图,看起来像一个随着进度增加而充满水的圆圈.

I want to build a progress view that look like a circle that fills with water as the progress increase.

为此,我制作了一个自定义的 Shape 来创建水,并添加了一个动画,该动画在该 Shape 上的波浪效果上会一直重复.为此,我想在进度增加的同时添加动画,以模拟水位增加.

To do that, I've made a custom Shape that create the water and I added an Animation that repeat forever to a wave effect on that Shape. With that I wanted to add an animation while the progress increase to simulate that the water level increases.

问题是当我触发最后一个动画时,它添加的 onAppear 动画将停止工作.有没有一种方法可以解决,使两个动画都组合在一起,然后 repeatForever 永不停止?这是一个例子:

The problem is that when I trigger this last animation, the one that it's added onAppear stop working. Is there a way to fix that so both animation are combining then the repeatForever one never stops ? Here is an example :

这是完整的代码:

struct WaterWaveView: View {
    @State var progress: CGFloat = 0.1
    @State var phase: CGFloat = 0.5

    var body: some View {
        VStack {
            WaterWave(progress: self.progress, phase: self.phase)
                .fill(Color.blue)
                .clipShape(Circle())
                .frame(width: 250, height: 250)
                .onAppear {
                    withAnimation(Animation.linear(duration: 1)
                                    .repeatForever(autoreverses: false)) {
                        self.phase = .pi * 2
                    }
                }
            Button("Add") {
                withAnimation(.easeOut(duration: 1)) {
                    self.progress += 0.1
                }
            }
            Button("Reset") {
                self.progress = 0.0
            }
        }
    }
}

struct WaterWave: Shape {
    var progress: CGFloat
    let amplitude: CGFloat = 10
    let waveLength: CGFloat = 20
    var phase: CGFloat

    var animatableData: AnimatablePair<CGFloat, CGFloat> {
        get { AnimatablePair(phase, progress) }
        set {
            phase = newValue.first
            progress = newValue.second
        }
    }

    func path(in rect: CGRect) -> Path {
        var path = Path()

        let width = rect.width
        let height = rect.height
        let midWidth = width / 2
        let progressHeight = height * (1 - progress)

        path.move(to: CGPoint(x: 0, y: progressHeight))

        for x in stride(from: 0, to: width, by: 10) {
            let relativeX = x/waveLength
//            let normalizedLength = relativeX / midWidth

            let normalizedLength = (x - midWidth) / midWidth
            let y = progressHeight + sin(phase + relativeX) * amplitude * normalizedLength
            path.addLine(to: CGPoint(x: x, y: y))
        }

        path.addLine(to: CGPoint(x: width, y: progressHeight))
        path.addLine(to: CGPoint(x: width, y: height))
        path.addLine(to: CGPoint(x: 0, y: height))
        path.addLine(to: CGPoint(x: 0, y: progressHeight))

        return path
    }
}

推荐答案

至少(到目前为止)不添加(累计)SwiftUI动画(SwiftUI 2.0).因此,这里有可能的解决方法.

SwiftUI animations are not added(cumulated), at least for now (SwiftUI 2.0). So here is possible workaround.

通过Xcode 12/iOS 14测试

Tested with Xcode 12 / iOS 14

struct WaterWaveView: View {
    @State var progress: CGFloat = 0.1
    @State var phase: CGFloat = 0.5

    var body: some View {
        VStack {
            WaterWave(progress: self.progress, phase: self.phase)
                .fill(Color.blue)
                .clipShape(Circle())
                .frame(width: 250, height: 250)
                .animation(phase == 0 ? .default : Animation.linear(duration: 1).repeatForever(autoreverses: false), value: phase)
                .animation(.easeOut(duration: 1), value: progress)
                .onAppear {
                            self.phase = .pi * 2
                }
            Button("Add") {
                    self.phase = 0
                    self.progress += 0.1
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                        self.phase = .pi * 2
                    }
            }
            Button("Reset") {
                self.progress = 0.0
            }
        }
    }
}

这篇关于使用Button触发的动画会停止在Appear中添加的repeatForever动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆