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
相关产品推荐
相关产品推荐

