SwiftUI:停止永远重复的动画

时间:2019-12-02 06:42:50

标签: swift xcode swiftui

我想在屏幕上显示各种“徽章”,当满足条件时,它将从正常大小反弹到更大,然后反复回到正常状态,直到不再满足条件为止。但是,我似乎无法让徽章停止“弹跳”。一旦启动,便无法阻止。

我尝试过的事情: 我尝试使用一些动画,但是可以将它们归类为使用“ repeatForever”实现所需效果的动画,而不是不使用它们的动画。例如:

Animation.default.repeatForever(autoreverses: true)

Animation.spring(response: 1, dampingFraction: 0, blendDuration: 1)(将阻尼设置为0可以永远消失)

其后是将其替换为.animation(nil)。似乎不起作用。有人有什么想法吗?提前非常感谢您!这是重现它的代码:

struct theProblem: View {
    @State var active: Bool = false

    var body: some View {
        Circle()
            .scaleEffect( active ? 1.08: 1)
            .animation( active ? Animation.default.repeatForever(autoreverses: true): nil )
            .frame(width: 100, height: 100)
            .onTapGesture {
                self.active = !self.active

        }
    }
}

2 个答案:

答案 0 :(得分:3)

我知道了!

使用 .repeatForever() 的动画,如果您将动画替换为 nil,则不会停止。 如果您将其替换为相同的动画但没有 .repeatForever(),它将停止。 (或者,也可以使用其他任何会停止的动画,因此您可以使用持续时间为0的线性动画来立即停止)

换句话说,这将不起作用:.animation(active ? Animation.default.repeatForever() : nil)

但这确实可行:.animation(active ? Animation.default.repeatForever() : Animation.default)

为了使它更具可读性和易用性,我将其放入了扩展名中,您可以像这样使用它: .animation(Animation.default.repeat(while: active))

这是一个使用我的扩展程序的交互式示例,您可以将其与实时预览一起使用来进行测试:

import SwiftUI

extension Animation {
    func `repeat`(while expression: Bool, autoreverses: Bool = true) -> Animation {
        if expression {
            return self.repeatForever(autoreverses: autoreverses)
        } else {
            return self
        }
    }
}

struct TheSolution: View {
    @State var active: Bool = false
    var body: some View {
        Circle()
            .scaleEffect( active ? 1.08: 1)
            .animation(Animation.default.repeat(while: active))
            .frame(width: 100, height: 100)
            .onTapGesture {
                self.active.toggle()
            }
    }
}

struct TheSolution_Previews: PreviewProvider {
    static var previews: some View {
        TheSolution()
    }
}

据我所知,一旦分配了动画,它就永远不会消失,直到您的View完全停止。因此,如果您将.default动画设置为永久重复并自动倒转,然后分配了一个持续时间为4的线性动画,您会注意到默认的重复动画仍在继续,但直到它移动的速度越来越慢在4秒结束时完全停止。因此,我们通过线性动画将默认动画设置为停止动画。

答案 1 :(得分:0)

您的代码没有错,所以我认为这是苹果的缺陷。似乎有很多隐式动画(至少在Xcode 11.2中)。无论如何...

我建议考虑以下提供预期行为的替代方法。

struct TestAnimationDeactivate: View {
    @State var active: Bool = false

    var body: some View {
        VStack {
            if active {
                BlinkBadge()
            } else {
                Badge()
            }
        }
        .frame(width: 100, height: 100)
        .onTapGesture {
            self.active.toggle()
        }
    }
}

struct Badge: View {
    var body: some View {
        Circle()
    }
}

struct BlinkBadge: View {
    @State private var animating = false
    var body: some View {
        Circle()
            .scaleEffect(animating ? 1.08: 1)
            .animation(Animation.default.repeatForever(autoreverses: true))
            .onAppear {
                self.animating = true
            }
    }
}

struct TestAnimationDeactivate_Previews: PreviewProvider {
    static var previews: some View {
        TestAnimationDeactivate()
    }
}