使用 SwiftUI 制作按钮闪烁动画

Okz*_*pes 10 xcode animation ios swift swiftui

如何在 SwiftUI 中制作边框颜色变化动画。这是 UIKit 的代码

extension UIButton{
    func blink(setColor: UIColor, repeatCount: Float, duration: Double) {
        self.layer.borderWidth = 1.0
        let animation: CABasicAnimation = CABasicAnimation(keyPath: "borderColor")
        animation.fromValue = UIColor.clear.cgColor
        animation.toValue = setColor.cgColor
        animation.duration = duration
        animation.autoreverses = true
        animation.repeatCount = repeatCount
        self.layer.borderColor = UIColor.clear.cgColor
        self.layer.add(animation, forKey: "")
    }
}
Run Code Online (Sandbox Code Playgroud)

Wil*_*ong 7

我在使用 SwiftUI 项目实现重复文本时遇到了类似的问题。答案看起来太先进了,我无法实施。经过一番搜索和研究。我设法反复闪烁我的文字。对于稍后看到这篇文章的人,您可以使用withAnimation{}和尝试这种方法.animation()

雨燕5

@State private var myRed = 0.2
@State private var myGreen = 0.2
@State private var myBlue = 0.2

var body:some View{
    
Button(action:{
 //
}){
 Text("blahblahblah")
}
.border(Color(red: myRed,green: myGreen,blue: myBlue))
.onAppear{
    withAnimation{
       myRed = 0.5
       myGreen = 0.5
       myBlue = 0
    }
}
.animation(Animation.easeInOut(duration:2).repeatForever(autoreverses:true))
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*afi 7

这太容易了。首先创建一个ViewModifier,以便我们可以在任何地方轻松使用它。

import SwiftUI

struct BlinkViewModifier: ViewModifier {
    
    let duration: Double
    @State private var blinking: Bool = false
    
    func body(content: Content) -> some View {
        content
            .opacity(blinking ? 0 : 1)
            .animation(.easeOut(duration: duration).repeatForever())
            .onAppear {
                withAnimation {
                    blinking = true
                }
            }
    }
}

extension View {
    func blinking(duration: Double = 0.75) -> some View {
        modifier(BlinkViewModifier(duration: duration))
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用,

// with duration 

Text("Hello, World!")
    .foregroundColor(.white)
    .padding()
    .background(Color.blue)
    .blinking(duration: 0.75) // here duration is optional. This is blinking time

// or (default is 0.75)

Text("Hello, World!")
    .foregroundColor(.white)
    .padding()
    .background(Color.blue)
    .blinking() 

Run Code Online (Sandbox Code Playgroud)


Asp*_*eri 3

更新:Xcode 13.4 / iOS 15.5

所提出的解决方案仍然可以通过一些最小的调整来工作。

更新的代码和演示在这里

原来的:

希望以下的方法能够对大家有所帮助。它基于ViewModifier,可以通过绑定来控制。动画的速度以及动画类型本身可以根据需要轻松更改。

注意:尽管存在一些观察到的缺点:由于动画 API 没有提供 didFinish 回调,因此使用了一些技巧来解决它;还观察到对 Animation.repeatCount 的一些奇怪处理,但这看起来像是 SwiftUI 问题。

无论如何,这是一个演示(开始时屏幕闪烁是预览的启动):a)在 onAppear 中激活闪烁 b)通过某种操作强制激活,在本例中是通过按钮

边框闪烁

struct BlinkingBorderModifier: ViewModifier {
    let state: Binding<Bool>
    let color: Color
    let repeatCount: Int
    let duration: Double

    // internal wrapper is needed because there is no didFinish of Animation now
    private var blinking: Binding<Bool> {
        Binding<Bool>(get: {
            DispatchQueue.main.asyncAfter(deadline: .now() + self.duration) {
                self.state.wrappedValue = false
            }
            return self.state.wrappedValue }, set: {
            self.state.wrappedValue = $0
        })
    }
    
    func body(content: Content) -> some View
    {
        content
            .border(self.blinking.wrappedValue ? self.color : Color.clear, width: 1.0)
            .animation( // Kind of animation can be changed per needs
                Animation.linear(duration:self.duration).repeatCount(self.repeatCount)
            )
    }
}

extension View {
    func blinkBorder(on state: Binding<Bool>, color: Color,
                     repeatCount: Int = 1, duration: Double = 0.5) -> some View {
        self.modifier(BlinkingBorderModifier(state: state, color: color,
                                             repeatCount: repeatCount, duration: duration))
    }
}

struct TestBlinkingBorder: View {
    @State  var blink = false
    var body: some View {
        VStack {
            Button(action: { self.blink = true }) {
                Text("Force Blinking")
            }
            Divider()
            Text("Hello, World!").padding()
                .blinkBorder(on: $blink, color: Color.red, repeatCount: 5, duration: 0.5)
        }
        .onAppear {
            self.blink = true
        }
    }
}
Run Code Online (Sandbox Code Playgroud)