How to combine shapes in SwiftUI?
Asked Answered
H

1

7

I need to create a shape from several other shapes, and ideally, I'd get a single shape struct at the end which would have two shapes stacked as ZStack would. I haven't noticed an obvious implementation of this anywhere, so maybe somebody has some ideas on how to implement it?

Here's what I want to have:

struct CustomShape: Shape {
    func path(in rect: CGRect) -> Path {
        // Add shapes here???? For example, combine Rectangle with Circle?
    }
}
Hess answered 18/4, 2020 at 23:37 Comment(0)
T
8

You can use func addPath(_ path: Path, transform: CGAffineTransform = .identity) to create a new Shape like this :

struct CustomShape: Shape {
    func path(in rect: CGRect) -> Path {
        var customShape = Path { p in
            p.move(to: CGPoint(x: 0, y: 0))
            p.addQuadCurve(to: CGPoint(x: 0, y: 100),
                           control: CGPoint(x: 0, y: 0))
            p.addCurve(to: CGPoint(x: 100, y: 400),
                       control1: CGPoint(x: 0, y: 200),
                       control2: CGPoint(x: 100, y: 200))
            p.addCurve(to: CGPoint(x: 200, y: 100),
                       control1: CGPoint(x: 100, y: 200),
                       control2: CGPoint(x: 200, y: 200))
            p.addQuadCurve(to: CGPoint(x: 200, y: 0),
                           control: CGPoint(x: 200, y: 0))
        }

        let rectangle = Rectangle()
            .path(in: customShape.boundingRect)
            .offsetBy(dx: 100, dy: 0)

        customShape.addPath(rectangle, transform: .init(scaleX: 0.5, y: 0.35))

        return customShape
    }
}

And use it like this :

struct SwiftUIView: View {
    var body: some View {
        CustomShape()
    }
}
Tripodic answered 19/4, 2020 at 0:23 Comment(2)
That's not an implementation of Shape you're creating, you're creating a ViewBourgeois
@NicolasMandica is correct, but what wasn't obvious to me was that you could access and modify SwiftUI's built-in Shape paths. To combine a Rectangle and Circle, in path closure: let rectangle = Rectangle().path(in: rect) .applying(CGAffineTransform(scaleX: 1, y: 0.5)) var circle = Circle().path(in: rect) circle.addPath(rectangle) path = circleCove

© 2022 - 2024 — McMap. All rights reserved.