在 SwiftUI 中绘制路径后填充形状

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

我尝试用以下形状来绘制迅捷的鸟。

struct SwiftBird: Shape {
    func path(in rect: CGRect) -> Path {
        let size = min(rect.width, rect.height)

        let path = Path { path in
            path.move(to: CGPoint(x: 0.565 * size, y: 0.145 * size))
            path.addQuadCurve(to: CGPoint(x: 0.79 * size, y: 0.62 * size), control: CGPointMake(0.85 * size, 0.34 * size))
            
            path.move(to: CGPoint(x: 0.79 * size, y: 0.62 * size))
            path.addQuadCurve(to: CGPoint(x: 0.845 * size, y: 0.825 * size), control: CGPointMake(0.88 * size, 0.75 * size))
            
            path.move(to: CGPoint(x: 0.1 * size, y: 0.58 * size))
            path.addQuadCurve(to: CGPoint(x: 0.5 * size, y: 0.82 * size), control: CGPointMake(0.25 * size, 0.8 * size))
            path.addQuadCurve(to: CGPoint(x: 0.67 * size, y: 0.775 * size), control: CGPointMake(0.6 * size, 0.82 * size))
            path.addQuadCurve(to: CGPoint(x: 0.845 * size, y: 0.825 * size), control: CGPointMake(0.78 * size, 0.715 * size))
            
            path.move(to: CGPoint(x: 0.1 * size, y: 0.58 * size))
            path.addQuadCurve(to: CGPoint(x: 0.525 * size, y: 0.63 * size), control: CGPointMake(0.325 * size, 0.735 * size))
            
            path.move(to: CGPoint(x: 0.175 * size, y: 0.25 * size))
            path.addQuadCurve(to: CGPoint(x: 0.525 * size, y: 0.63 * size), control: CGPointMake(0.305 * size, 0.445 * size))
            
            path.move(to: CGPoint(x: 0.175 * size, y: 0.25 * size))
            path.addQuadCurve(to: CGPoint(x: 0.475 * size, y: 0.475 * size), control: CGPointMake(0.36 * size, 0.405 * size))
            
            path.move(to: CGPoint(x: 0.26 * size, y: 0.205 * size))
            path.addQuadCurve(to: CGPoint(x: 0.475 * size, y: 0.475 * size), control: CGPointMake(0.4 * size, 0.405 * size))
            
            path.move(to: CGPoint(x: 0.26 * size, y: 0.205 * size))
            path.addQuadCurve(to: CGPoint(x: 0.63 * size, y: 0.505 * size), control: CGPointMake(0.465 * size, 0.405 * size))
            
            path.move(to: CGPoint(x: 0.565 * size, y: 0.145 * size))
            path.addQuadCurve(to: CGPoint(x: 0.63 * size, y: 0.505 * size), control: CGPointMake(0.7 * size, 0.355 * size))
        }

        return path
    }
}

我在另一个视图中添加鸟的图画并为其设置动画,如下所示:

struct TestView: View {
    @State private var percentage: CGFloat = 0
    
    var body: some View {
        ZStack {
            Color(.black)
            SwiftBird()
                .trim(from: 0, to: percentage)
                .stroke(Color.white, style: StrokeStyle(lineWidth: 1, lineCap: .round, lineJoin: .round))
                .frame(width: 100, height: 100)
                .animation(.easeInOut(duration: 5.0), value: percentage)
                .onAppear {
                    self.percentage = 1.0
                }
        }
    }
}

一旦路径绘制完成,我想用颜色填充形状。但是,如果我将

.fill(Color.orange)
修改器应用于形状,它不会正确填充内部形状。我可以看到形状内部的黑色区域,并且颜色超出了路径。如何实现动画的颜色填充?如有任何帮助,我们将不胜感激。

swift swiftui drawing
1个回答
1
投票

填充后你的形状看起来像这样:

问题在于您的形状不是单个封闭的子路径。这是一堆互不相连的子路径。每个

move(to:)
都会启动一个新的子路径。当您填充形状时,每个子路径都会关闭并单独填充。徽标的大部分内部不被任何子路径包围,并且一些外部is被单独封闭的子路径包围。

这是创建单个封闭子路径的版本:

struct SwiftBird: Shape {
    func path(in rect: CGRect) -> Path {
        let size = min(rect.width, rect.height)
        var path = Path()

        path.move(to: CGPoint(x: 0.565, y: 0.145))
        for (ex, ey, cx, cy): (CGFloat, CGFloat, CGFloat, CGFloat) in [
            (0.79, 0.62, 0.85, 0.34), // Upper wing outside
            (0.845, 0.825, 0.88, 0.75), // Head top
            (0.67, 0.775, 0.78, 0.715), // Head bottom
            (0.5, 0.82, 0.6, 0.82), // Lower shoulder
            (0.1, 0.58, 0.25, 0.8), // Lower wing outside
            (0.525, 0.63, 0.325, 0.735), // Lower wing inside
            (0.175, 0.25, 0.305, 0.445), // Lower tail outside
            (0.475, 0.475, 0.36, 0.405), // Lower tail inside
            (0.26, 0.205, 0.4, 0.405), // Upper tail inside
            (0.63, 0.505, 0.465, 0.405), // Upper tail outside
            (0.565, 0.145, 0.7, 0.355), // Upper wing inside
        ] {
            path.addQuadCurve(
                to: CGPoint(x: ex, y: ey),
                control: CGPoint(x: cx, y: cy)
            )
        }

        path.closeSubpath()
        path = path.applying(.init(scaleX: size, y: size))
        return path
    }
}

抚摸时看起来和你的一样:

但填写正确:

让 SwiftUI 在动画末尾精确填充徽标的一种方法是将其包装在自定义

Animatable
View
:

struct AnimatedSwiftLogo: View, Animatable {
    var animatableData: Double

    var body: some View {
        ZStack {
            SwiftBird()
                .fill(animatableData == 1 ? .orange : .clear)
            SwiftBird()
                .trim(from: 0, to: animatableData)
                .stroke(Color.white, style: StrokeStyle(lineWidth: 1, lineCap: .round, lineJoin: .round))
        }
    }
}

struct TestView: View {
    @State private var percentage: CGFloat = 0
    
    var body: some View {
        ZStack {
            Color(.black)
            AnimatedSwiftLogo(animatableData: percentage)
                .frame(width: 100, height: 100)
                .animation(.easeInOut(duration: 5.0), value: percentage)
                .onAppear {
                    self.percentage = 1.0
                }
        }
    }
}

结果:

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