我正在使用以下代码通过圆圈和复选标记显示成功

struct CheckMarkView: View {
    @State var borderInit: Bool = false
    @State var spinArrow: Bool = false
    @State var dismissArrow: Bool = false
    @State var displayCheckmark: Bool = false
    
    var body: some View {
        ZStack {
            Circle()
                .strokeBorder(style: StrokeStyle(lineWidth: borderInit ? 10 : 64))
                .frame(width: 128, height: 128)
                .foregroundColor(borderInit ? .white : .black)
                .animation(.easeOut(duration: 3).speed(1.5))
                .onAppear() {
                    borderInit.toggle()
                }
            
            // Arrow Icon
            Image(systemName: "arrow.2.circlepath")
                .frame(width: 80, height: 80)
                .font(.largeTitle)
                .foregroundColor(.white)
                .rotationEffect(.degrees(spinArrow ? 360 : -360))
                .opacity(dismissArrow ? 0 : 1)
                .animation(.easeOut(duration: 2))
                .onAppear() {
                    spinArrow.toggle()
                    withAnimation(Animation.easeInOut(duration: 1).delay(1)) {
                        self.dismissArrow.toggle()
                    }
                }
            
            // Checkmark
            Path { path in
                path.move(to: CGPoint(x: 20, y: -40))
                path.addLine(to: CGPoint(x: 40, y: -20))
                path.addLine(to: CGPoint(x: 80, y: -60))
            }
            .trim(from: 0, to: displayCheckmark ? 1 : 0)
            .stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
            .foregroundColor(displayCheckmark ? .white : .black)
            .offset(x: 150, y: 420)
            //.animation(.spring(.bouncy, blendDuration: 2).delay(2))
            .animation(Animation.interpolatingSpring(stiffness: 150, damping: 10, initialVelocity: 0).delay(2))
            //.animation(Animation.interpolatingSpring(mass: 1, stiffness: 100, damping: 10, initialVelocity: 0).delay(2))
            .onAppear() {
                displayCheckmark.toggle()
            }
            
        }
        .background(.black)
    }
}

当我try 将框架添加到CheckMarkView时,图像和圆圈会显示在不同的位置.复选标记应显示在圆圈内.此外,复选标记动画结束时也不光滑.如何解决这个问题?如有任何帮助,我们将不胜感激.

推荐答案

您应该将勾选标记为Shape.这样,SwiftUI就可以为您处理布局,并且您不需要使用offset将其放在正确的位置.

以下是Shape实现的示例,基于您的Path中的点

struct CheckmarkShape: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let fifthWidth = rect.width / 5
        let quarterHeight = rect.height / 4
        path.move(to: .init(x: rect.minX + fifthWidth, y: rect.minY + 2 * quarterHeight))
        path.addLine(to: .init(x: rect.minX + 2 * fifthWidth, y: rect.minY + 3 * quarterHeight))
        path.addLine(to: .init(x: rect.minX + 4 * fifthWidth, y: rect.minY + quarterHeight))
        return path
    }
}

CheckmarkView可能看起来像这样:

@State var borderInit: Bool = false
@State var spinArrow: Bool = false
@State var dismissArrow: Bool = false
@State var displayCheckmark: Bool = false

var body: some View {
    ZStack {
        Color.black.ignoresSafeArea()
        Circle()
            .strokeBorder(style: StrokeStyle(lineWidth: borderInit ? 10 : 64))
            .frame(width: 128, height: 128)
            .foregroundColor(borderInit ? .white : .black)
            .animation(.easeOut(duration: 3).speed(1.5), value: borderInit)
            .onAppear() {
                borderInit.toggle()
            }
        
        // Arrow Icon
        Image(systemName: "arrow.2.circlepath")
            .frame(width: 80, height: 80)
            .font(.largeTitle)
            .foregroundColor(.white)
            .rotationEffect(.degrees(spinArrow ? 360 : -360))
            .opacity(dismissArrow ? 0 : 1)
            .animation(.easeOut(duration: 2), value: dismissArrow)
            .animation(.easeOut(duration: 2), value: spinArrow)
            .onAppear() {
                spinArrow.toggle()
                withAnimation(Animation.easeInOut(duration: 1).delay(1)) {
                    self.dismissArrow.toggle()
                }
            }
        CheckmarkShape()
            .trim(from: 0, to: displayCheckmark ? 1 : 0)
            .stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
            .frame(width: 100, height: 100)
            .foregroundColor(displayCheckmark ? .white : .black)
            .animation(.bouncy.delay(2), value: displayCheckmark)
            .onAppear() {
                displayCheckmark.toggle()
            }
    }
}

您应该将value参数传递给所有animation修饰符.不含value的版本已被弃用.

由于您使用了 spring 动画,因此我假设您希望复选标记的笔画在其应该结束的地方移动一点beyond,然后反弹.您可以通过扩展Shape实现中的箭头路径并将trim动画为小于1的内容来实现这一点.

struct CheckmarkShape: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let fifthWidth = rect.width / 5
        let quarterHeight = rect.height / 4
        path.move(to: .init(x: rect.minX + fifthWidth, y: rect.minY + 2 * quarterHeight))
        path.addLine(to: .init(x: rect.minX + 2 * fifthWidth, y: rect.minY + 3 * quarterHeight))
        path.addLine(to: .init(x: rect.minX + 5 * fifthWidth, y: rect.minY))
        return path
    }
}
.trim(from: 0, to: displayCheckmark ? 0.75 : 0)

Swift相关问答推荐

如何模拟可以立即返回和/或与Deliverc/await同步返回的CompletionButtons风格代码?

操作员如何点逻辑非(.!)在Swift工作?

SwiftUI正在初始化不带状态变量的绑定变量

它是RxSwift中直接用于可扩展视图的有效的可扩展BehaviorRelay值?

一种函数,用于判断变量的类型是否为在SWIFT中作为参数传递的类型

是否可以使用一个 NSRegularExpression 同时判断字符串格式并提取子字符串?

应该在ViewModel还是ViewController中使用"Task {}"?

如何使一个 Reality Composer 场景中的分组对象可拖动?

如何在 macOS/AppKit 的窗口选项卡上接受拖动项目的放置?

如何在不提交到应用store 的情况下在本地运行我的应用

SwiftUI 分段 Select 器的问题

将基于MyProtocol的泛型函数的参数更改为使用存在的any MyProtocol或some MyProtocol是否会受到惩罚?

响应 UITextField (UIViewRepresentable) 中的特定按键

异步等待不会在项目中触发,但在 Xcode playground 中工作正常

RealityKit – 无法加载 ARView(发现为零)

如何快速判断设备方向是横向还是横向?

Xcode 6 中的嵌入式内容包含 Swift 代码构建设置有什么作用?

我可以在 Swift 中为泛型类型 T 分配默认类型吗?

如何在 Swift 中复制字典?

Swift 中惰性 var 的优势是什么