You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI如何将图片裁剪为自定义Shape并沿指定路径实现动画

实现方案

这个需求完全可以实现,根据你要的效果可以选以下两种实现方式:

方式1:图片沿路径逐步裁剪显示(和描边动画同步露出)

如果你要的是图片像描边一样沿着自定义路径逐渐显示出来,直接用mask修饰符绑定你已经写好的loadingPath和trim参数即可,不需要额外做路径位置计算:

struct LoadingView: View {
    @State private var x: CGFloat = 0
    // 你原有的自定义路径,遵循Swift规范调整首字母大写
    struct LoadingPath: Shape {
        func path(in rect: CGRect) -> Path {
            Path { path in
                path.move(to: CGPoint(x: rect.midX, y: rect.midY))
                path.addQuadCurve(to: CGPoint(x: 230, y: 200), control: CGPoint(x: -100, y: 300))
                path.addQuadCurve(to: CGPoint(x: 90, y: 400), control: CGPoint(x: 400, y: 130))
                path.addLine(to: CGPoint(x: 90, y: 600))
            }
        }
    }
    
    var body: some View {
        ZStack {
            // 替换为你自己的图片资源
            Image("your_image_name")
                .resizable()
                .scaledToFill()
                .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
                // 核心逻辑:用自定义路径做遮罩,绑定trim参数同步动画
                .mask {
                    LoadingPath()
                        .trim(from: 0, to: x)
                        // 调整lineWidth控制显示的路径粗细
                        .stroke(lineWidth: 50)
                }
            
            // 如果需要显示路径描边就保留这部分,要隐藏的话直接注释掉,或者把Color.purple改成和背景同色
            LoadingPath()
                .trim(from: 0, to: x)
                .stroke(Color.purple, lineWidth: 2)
                .onAppear() {
                    withAnimation(Animation.easeInOut(duration: 3).delay(0.5)) {
                        self.x = 1
                    }
                }
        }
        .ignoresSafeArea()
    }
}

方式2:完整图片沿路径移动

如果你要的是整张图片作为元素沿着路径轨迹移动,只需要扩展Path获取指定进度下的点位坐标,同步给图片做偏移即可:

extension Path {
    // 获取指定trim比例下的路径点坐标
    func point(at percent: CGFloat) -> CGPoint? {
        let trimmed = self.trimmedPath(from: 0, to: percent)
        return trimmed.currentPoint
    }
}

struct LoadingView: View {
    @State private var x: CGFloat = 0
    struct LoadingPath: Shape {
        func path(in rect: CGRect) -> Path {
            Path { path in
                path.move(to: CGPoint(x: rect.midX, y: rect.midY))
                path.addQuadCurve(to: CGPoint(x: 230, y: 200), control: CGPoint(x: -100, y: 300))
                path.addQuadCurve(to: CGPoint(x: 90, y: 400), control: CGPoint(x: 400, y: 130))
                path.addLine(to: CGPoint(x: 90, y: 600))
            }
        }
    }
    
    // 提前计算全尺寸下的完整路径
    private let animationPath = LoadingPath().path(in: UIScreen.main.bounds)
    
    var body: some View {
        ZStack {
            // 要移动的图片,可自行调整尺寸
            Image("your_image_name")
                .resizable()
                .frame(width: 40, height: 40)
                // 同步路径点位做偏移
                .offset(
                    x: animationPath.point(at: x)?.x ?? 0,
                    y: animationPath.point(at: x)?.y ?? 0
                )
            
            // 路径描边,不需要的话直接删除即可
            LoadingPath()
                .trim(from: 0, to: x)
                .stroke(Color.purple, lineWidth: 2)
                .onAppear() {
                    withAnimation(Animation.easeInOut(duration: 3).delay(0.5)) {
                        self.x = 1
                    }
                }
        }
        .ignoresSafeArea()
    }
}

注意事项

  • 你原有的路径坐标写死了固定数值,如果要适配不同尺寸的屏幕,建议把固定坐标改成基于传入的rect参数计算的相对值
  • 如果需要隐藏路径描边,直接删除stroke部分的代码即可,不会影响图片的动画效果

内容的提问来源于stack exchange,提问作者Nokt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 20:06:03