在 SwiftUI 中用波浪动画填充圆圈

Posted

技术标签:

【中文标题】在 SwiftUI 中用波浪动画填充圆圈【英文标题】:Fill circle with wave animation in SwiftUI 【发布时间】:2020-08-13 14:11:07 【问题描述】:

我在 swiftUI 中创建了一个圆圈,我想用正弦波动画填充它以实现水波效果/动画。我想用类似的外观填充它:

下面是我的代码:

import SwiftUI

struct CircleWaveView: View 
    var body: some View 
        Circle()
            .stroke(Color.blue, lineWidth: 10)
            .frame(width: 300, height: 300)
    


struct CircleWaveView_Previews: PreviewProvider 
    static var previews: some View 
        CircleWaveView()
    


我想主要在 SwiftUI 上实现它,以便我可以支持暗模式!感谢您的帮助!

【问题讨论】:

【参考方案1】:

这是一个完整的独立示例。它具有一个滑块,可让您更改百分比:

import SwiftUI

struct ContentView: View 
    
    @State private var percent = 50.0
    
    var body: some View 
        VStack 
            CircleWaveView(percent: Int(self.percent))
            Slider(value: self.$percent, in: 0...100)
        
        .padding(.all)
    


struct Wave: Shape 

    var offset: Angle
    var percent: Double
    
    var animatableData: Double 
        get  offset.degrees 
        set  offset = Angle(degrees: newValue) 
    
    
    func path(in rect: CGRect) -> Path 
        var p = Path()

        // empirically determined values for wave to be seen
        // at 0 and 100 percent
        let lowfudge = 0.02
        let highfudge = 0.98
        
        let newpercent = lowfudge + (highfudge - lowfudge) * percent
        let waveHeight = 0.015 * rect.height
        let yoffset = CGFloat(1 - newpercent) * (rect.height - 4 * waveHeight) + 2 * waveHeight
        let startAngle = offset
        let endAngle = offset + Angle(degrees: 360)
        
        p.move(to: CGPoint(x: 0, y: yoffset + waveHeight * CGFloat(sin(offset.radians))))
        
        for angle in stride(from: startAngle.degrees, through: endAngle.degrees, by: 5) 
            let x = CGFloat((angle - startAngle.degrees) / 360) * rect.width
            p.addLine(to: CGPoint(x: x, y: yoffset + waveHeight * CGFloat(sin(Angle(degrees: angle).radians))))
        
        
        p.addLine(to: CGPoint(x: rect.width, y: rect.height))
        p.addLine(to: CGPoint(x: 0, y: rect.height))
        p.closeSubpath()
        
        return p
    


struct CircleWaveView: View 
    
    @State private var waveOffset = Angle(degrees: 0)
    let percent: Int
    
    var body: some View 

        GeometryReader  geo in
            ZStack 
                Text("\(self.percent)%")
                    .foregroundColor(.black)
                    .font(Font.system(size: 0.25 * min(geo.size.width, geo.size.height) ))
                Circle()
                    .stroke(Color.blue, lineWidth: 0.025 * min(geo.size.width, geo.size.height))
                    .overlay(
                        Wave(offset: Angle(degrees: self.waveOffset.degrees), percent: Double(percent)/100)
                            .fill(Color(red: 0, green: 0.5, blue: 0.75, opacity: 0.5))
                            .clipShape(Circle().scale(0.92))
                    )
            
        
        .aspectRatio(1, contentMode: .fit)
        .onAppear 
            withAnimation(Animation.linear(duration: 2).repeatForever(autoreverses: false)) 
            self.waveOffset = Angle(degrees: 360)
            
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        CircleWaveView(percent: 58)
    

【讨论】:

嗨@vacawama。我怎样才能在水滴(不是圆形)的图像中实现相同的效果? @varoons,如果你的水滴是Shape,你应该可以在上面的代码中用WaterDrop()替换Circle()

以上是关于在 SwiftUI 中用波浪动画填充圆圈的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中暂停动画?

SwiftUI:通过更新变量来动画波浪不起作用

如何摆脱不需要的 SwiftUI 动画?

SwiftUI 奇怪的动画行为与 systemImage

SwiftUI 创建动画圈

如何动画一个圆圈来填充而不是使用.trim?