多个形状的 SwiftUI 动画无法正常工作

问题描述 投票:0回答:2

我试图将不同的形状显示为一个接一个的路径动画。动画应该始终从不显示任何内容开始到完成的形状。 我的问题是它只适用于第一个形状,我想是因为

onAppear
。但是,单击“下一个”按钮后,下一个形状不会产生动画。 我尝试使用
pathProgress
值和另一个布尔值,但它要么根本不动画,要么向后动画。

import SwiftUI

struct ContentView: View {
    @State var id = 1
    @State var pathProgress = 0.0
    
    var body: some View {
        VStack {
            ConsonantDrawing(id: id)
                .trim(from: 0, to: pathProgress)
                .stroke(Color.red, style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
                .animation(.linear(duration: 4.0), value: pathProgress)
                .onAppear {
                    pathProgress = 1.0
                }
                .frame(width: UIScreen.main.bounds.width * 0.5, height: UIScreen.main.bounds.height * 0.5)
            
            Spacer()
            
            HStack {
                Button {
                    id -= 1
                } label: {
                    Image(systemName: "arrow.backward.circle")
                }
                
                Spacer()
                
                Button {
                    id += 1
                } label: {
                    Image(systemName: "arrow.forward.circle")
                }
            }
            .padding()
            .font(.largeTitle)
        }
    }
}

struct ConsonantDrawing: Shape {
    var id: Int
    
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let width = rect.size.width
        let height = rect.size.height
        
        switch id {
        case 1:
            path.move(to: CGPoint(x: 0.12069*width, y: 0.97451*height))
            path.addLine(to: CGPoint(x: 0.12069*width, y: 0.52102*height))
            path.addCurve(to: CGPoint(x: 0.36207*width, y: 0.33497*height), control1: CGPoint(x: 0.12069*width, y: 0.38149*height), control2: CGPoint(x: 0.36207*width, y: 0.33497*height))
            path.addCurve(to: CGPoint(x: 0.03448*width, y: 0.27684*height), control1: CGPoint(x: 0.2069*width, y: 0.28846*height), control2: CGPoint(x: 0.03448*width, y: 0.27684*height))
            path.addCurve(to: CGPoint(x: 0.98276*width, y: 0.27684*height), control1: CGPoint(x: 0.03448*width, y: -0.02549*height), control2: CGPoint(x: 0.94828*width, y: -0.09526*height))
            path.addLine(to: CGPoint(x: 0.98276*width, y: 0.97451*height))
            
        case 2:
            path.move(to: CGPoint(x: 0.04412*width, y: 0.24668*height))
            path.addCurve(to: CGPoint(x: 0.27941*width, y: 0.19048*height), control1: CGPoint(x: 0.08154*width, y: 0.17525*height), control2: CGPoint(x: 0.20588*width, y: 0.15476*height))
            path.addCurve(to: CGPoint(x: 0.35294*width, y: 0.34524*height), control1: CGPoint(x: 0.35294*width, y: 0.22619*height), control2: CGPoint(x: 0.38079*width, y: 0.28888*height))
            path.addCurve(to: CGPoint(x: 0.20588*width, y: 0.42857*height), control1: CGPoint(x: 0.32353*width, y: 0.40476*height), control2: CGPoint(x: 0.26471*width, y: 0.42857*height))
            path.addCurve(to: CGPoint(x: 0.04412*width, y: 0.32143*height), control1: CGPoint(x: 0.14706*width, y: 0.42857*height), control2: CGPoint(x: 0.05882*width, y: 0.40476*height))
            path.addCurve(to: CGPoint(x: 0.07353*width, y: 0.15476*height), control1: CGPoint(x: 0.02941*width, y: 0.2381*height), control2: CGPoint(x: 0.05588*width, y: 0.19048*height))
            path.addCurve(to: CGPoint(x: 0.35294*width, y: 0.04762*height), control1: CGPoint(x: 0.10294*width, y: 0.09524*height), control2: CGPoint(x: 0.23438*width, y: 0.04762*height))
            path.addCurve(to: CGPoint(x: 0.63235*width, y: 0.19048*height), control1: CGPoint(x: 0.47059*width, y: 0.04762*height), control2: CGPoint(x: 0.60294*width, y: 0.08333*height))
            path.addCurve(to: CGPoint(x: 0.57353*width, y: 0.39286*height), control1: CGPoint(x: 0.65523*width, y: 0.27381*height), control2: CGPoint(x: 0.61001*width, y: 0.34856*height))
            path.addCurve(to: CGPoint(x: 0.47059*width, y: 0.58333*height), control1: CGPoint(x: 0.51471*width, y: 0.46429*height), control2: CGPoint(x: 0.47059*width, y: 0.53571*height))
            path.addCurve(to: CGPoint(x: 0.47059*width, y: 0.83333*height), control1: CGPoint(x: 0.47059*width, y: 0.62143*height), control2: CGPoint(x: 0.47059*width, y: 0.78571*height))
            path.addCurve(to: CGPoint(x: 0.98529*width, y: 0.83333*height), control1: CGPoint(x: 0.47059*width, y: 1.02381*height), control2: CGPoint(x: 0.95588*width, y: 1.04762*height))
            path.addCurve(to: CGPoint(x: 0.98529*width, y: 0.0119*height), control1: CGPoint(x: 0.98529*width, y: 0.60714*height), control2: CGPoint(x: 0.98529*width, y: 0.19048*height))
            
        case 3:
            path.move(to: CGPoint(x: 0.03186*width, y: 0.38372*height))
            path.addCurve(to: CGPoint(x: 0.27056*width, y: 0.27907*height), control1: CGPoint(x: 0.04505*width, y: 0.25581*height), control2: CGPoint(x: 0.19913*width, y: 0.25581*height))
            path.addCurve(to: CGPoint(x: 0.34199*width, y: 0.44186*height), control1: CGPoint(x: 0.34199*width, y: 0.30233*height), control2: CGPoint(x: 0.36904*width, y: 0.38681*height))
            path.addCurve(to: CGPoint(x: 0.17056*width, y: 0.51163*height), control1: CGPoint(x: 0.31341*width, y: 0.5*height), control2: CGPoint(x: 0.24198*width, y: 0.52326*height))
            path.addCurve(to: CGPoint(x: 0.03186*width, y: 0.38372*height), control1: CGPoint(x: 0.09913*width, y: 0.5*height), control2: CGPoint(x: 0.04615*width, y: 0.46512*height))
            path.closeSubpath()
            path.move(to: CGPoint(x: 0.03186*width, y: 0.38372*height))
            path.addCurve(to: CGPoint(x: 0.07056*width, y: 0.19767*height), control1: CGPoint(x: 0.01758*width, y: 0.30233*height), control2: CGPoint(x: 0.05341*width, y: 0.23256*height))
            path.addCurve(to: CGPoint(x: 0.24198*width, y: 0.05814*height), control1: CGPoint(x: 0.09913*width, y: 0.13953*height), control2: CGPoint(x: 0.17056*width, y: 0.0814*height))
            path.addCurve(to: CGPoint(x: 0.37056*width, y: 0.15116*height), control1: CGPoint(x: 0.29913*width, y: 0.09302*height), control2: CGPoint(x: 0.24198*width, y: 0.05814*height))
            path.addCurve(to: CGPoint(x: 0.49913*width, y: 0.05814*height), control1: CGPoint(x: 0.49913*width, y: 0.05814*height), control2: CGPoint(x: 0.41341*width, y: 0.11628*height))
            path.addCurve(to: CGPoint(x: 0.65627*width, y: 0.19767*height), control1: CGPoint(x: 0.61341*width, y: 0.09302*height), control2: CGPoint(x: 0.64413*width, y: 0.1532*height))
            path.addCurve(to: CGPoint(x: 0.54615*width, y: 0.47674*height), control1: CGPoint(x: 0.67849*width, y: 0.27907*height), control2: CGPoint(x: 0.58159*width, y: 0.43348*height))
            path.addCurve(to: CGPoint(x: 0.48484*width, y: 0.62791*height), control1: CGPoint(x: 0.5277*width, y: 0.49927*height), control2: CGPoint(x: 0.48484*width, y: 0.5814*height))
            path.addCurve(to: CGPoint(x: 0.48484*width, y: 0.81395*height), control1: CGPoint(x: 0.48484*width, y: 0.66512*height), control2: CGPoint(x: 0.48484*width, y: 0.76744*height))
            path.addCurve(to: CGPoint(x: 0.98484*width, y: 0.81395*height), control1: CGPoint(x: 0.48484*width, y: 1.02326*height), control2: CGPoint(x: 0.95627*width, y: 1.02326*height))
            path.addCurve(to: CGPoint(x: 0.98484*width, y: 0.02326*height), control1: CGPoint(x: 0.98484*width, y: 0.59302*height), control2: CGPoint(x: 0.98484*width, y: 0.19767*height))
            
        default:
            path.move(to: CGPoint(x: 0.12069*width, y: 0.97451*height))
            path.addLine(to: CGPoint(x: 0.12069*width, y: 0.52102*height))
        }
        
        return path
    }
}
animation swiftui path shapes
2个回答
0
投票
每次变化时,

.animation(.linear(duration: 4.0), value: pathProgress)
都会动画
pathProgress
。你似乎不想要那样。据我了解,当
pathProgress
设置为 0 时,您不需要动画 - 它应该仅在
pathProgress
设置为 1 时动画。

所以你应该删除

.animation(.linear(duration: 4.0), value: pathProgress)
。当您想要制作动画时,请使用
withAnimation
,当您不想制作动画时,请不要使用它。

VStack {
    ConsonantDrawing(id: id)
        .trim(from: 0, to: pathProgress)
        .stroke(Color.red, style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
        .onAppear {
            withAnimation(.linear(duration: 4.0)) {
                pathProgress = 1.0
            }
        }
    
    Spacer()
    
    HStack {
        Button {
            id -= 1
            pathProgress = 0
            withAnimation(.linear(duration: 4.0)) {
                pathProgress = 1.0
            }
        } label: {
            Image(systemName: "arrow.backward.circle")
        }
        
        Spacer()
        
        Button {
            id += 1
            pathProgress = 0
            withAnimation(.linear(duration: 4.0)) {
                pathProgress = 1.0
            }
        } label: {
            Image(systemName: "arrow.forward.circle")
        }
    }
    .padding()
    .font(.largeTitle)
}

0
投票

问题是您没有重置

pathProgress
。我所做的是在按下后退或下一个按钮时重置它,并检查当前的
id
是第一个还是最后一个,以避免动画问题。 我还删除了
.animation
视图上的
ConsonantDrawing
修改器,因为它会导致问题,并将动画放在操作中:

struct ContentView: View {
    
    @State var id = 1
    @State var pathProgress = 0.0
    
    var body: some View {
        VStack {
            ConsonantDrawing(id: id)
                .trim(from: 0, to: pathProgress)
                .stroke(Color.red, style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
                /// Remove this .animation line because is part of the issue!
                //.animation(.linear(duration: 4.0), value: pathProgress)
                .frame(width: UIScreen.main.bounds.width * 0.5, height: UIScreen.main.bounds.height * 0.5)
            
            Spacer()
            
            HStack {
                Button {
                    guard id != 1 else { return }
                    id -= 1
                    pathProgress = 0
                    withAnimation(.linear(duration: 4)) {
                        pathProgress = 1.0
                    }
                } label: {
                    Image(systemName: "arrow.backward.circle")
                }
                
                Spacer()
                
                Button {
                    guard id != 3 else { return }
                    pathProgress = 0
                    id += 1
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                        withAnimation(.linear(duration: 4)) {
                            pathProgress = 1.0
                        }
                    }
                } label: {
                    Image(systemName: "arrow.forward.circle")
                }
            }
            .padding()
            .font(.largeTitle)
        }
        .onAppear {
            print("On appear")
            withAnimation(.linear(duration: 4)) {
                pathProgress = 1.0
            }
        }
    }
}

结果如下:

让我知道您是如何找到这个解决方案的!

© www.soinside.com 2019 - 2024. All rights reserved.