ios 如何在SwiftUI中以Angular 和圆弧绘制线条

7rtdyuoh  于 11个月前  发布在  iOS
关注(0)|答案(2)|浏览(150)

我试着画一个相当基本的鸟的形状。我用圆圈来画身体,我试着画上喙(用红色突出显示),就像下面的参考图片所示。
图片参考:
x1c 0d1x的数据

struct Beak: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.move(to: CGPoint(x: rect.width/4, y: rect.height/2))
        path.addLine(to: CGPoint(x: 0, y: rect.height/2))
        // draw a line back to the circumference at a given angle
        // & close it with an arc along the circumference of the Body circle
        path.addLine(to: ??) 
        return path
    }
}

struct BirdView: View {
    var body: some View {
        ZStack {
            // MARK: Body
            Circle()
                .stroke(lineWidth: 10)
                .frame(width: 150)
                .overlay(alignment: .center) {
                    Circle()
                        .fill(.yellow)
                }
            
            // MARK: Beak
            Beak()
                .stroke(lineWidth: 5)
            
        }
        .frame(width: 300, height: 300)
        .background(.orange)
    }
}

字符串
我试图实现的是喙也关闭与弧沿着身体圆周,使我可以动画它以后与旋转,以模拟喙打开/关闭。任何帮助是感激。

gfttwv5a

gfttwv5a1#

如果你使用.addArc来绘制曲线位,那么就没有太多了。如果你使用中间点作为弧的起点,然后使用.offset将最终形状移动到适当的位置,那么可能会更容易。这也为稍后添加旋转效果做好了准备。
为了保持鸟头的特征在一起,您可以将它们全部应用为基圆的叠加,或者您可以将它们构建在单独的ZStack中。在单独的ZStack中进行可能更简单,这个ZStack的帧大小可以用于确定圆的大小以及眼睛和喙。
以下是经过调整的Shape

struct Beak: Shape {
    let angleDegrees: CGFloat
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.move(to: CGPoint(x: rect.midX, y: rect.midY))
        path.addArc(
            center: CGPoint(x: rect.maxX, y: rect.midY),
            radius: rect.midX,
            startAngle: .degrees(180),
            endAngle: .degrees(180 + angleDegrees),
            clockwise: angleDegrees < 0
        )
        path.addLine(to: CGPoint(x: 0, y: rect.midY))
        path.closeSubpath()
        return path
    }
}

字符串
下面是你如何使用它。我忍不住给它做了动画,

struct BirdView: View {
    @State private var gapeAngle = Angle.zero

    private func birdHead(diameter: CGFloat) -> some View {
        ZStack {
            Circle()
                .fill(.yellow)

            Circle()
                .stroke(lineWidth: 5)

            // Eye
            Ellipse()
                .fill(.black)
                .frame(width: diameter / 5, height: diameter / 5.55)
                .offset(x: -diameter / 4.7, y: -diameter / 5.35)

            // Upper beak
            Beak(angleDegrees: 20)
                .stroke(style: .init(lineWidth: 5, lineJoin: .round))
                .foregroundStyle(.red)
                .offset(x: -diameter / 2)
                .rotationEffect(gapeAngle)

            // Lower beak
            Beak(angleDegrees: -20)
                .stroke(style: .init(lineWidth: 5, lineJoin: .round))
                .foregroundStyle(.red)
                .offset(x: -diameter / 2)
                .rotationEffect(-gapeAngle)
        }
        .frame(width: diameter, height: diameter)
    }

    var body: some View {
        birdHead(diameter: 150)
            .padding(.leading, 50)
            .frame(width: 300, height: 300)
            .background(.orange)
            .onAppear {
                withAnimation(.easeInOut.repeatForever(autoreverses: true)) {
                    gapeAngle = .degrees(5)
                }
            }
    }
}


的数据

os8fio9y

os8fio9y2#

我不需要做数学运算来计算如何画出圆弧,而是使用subtracting从直角三角形中“减去”圆。

struct Beak: Shape {
    let radius: CGFloat // this is the radius of the circle to be subtracted
    let angle: Angle
    func path(in rect: CGRect) -> Path {
        // first draw a right-angled triangle where the two short edges
        // intersect at the middle of rect
        var path = Path()
        path.move(to: CGPoint(x: rect.midX, y: rect.midY))
        path.addLine(to: CGPoint(x: rect.minX, y: rect.midY))
        let ratio = tan(angle.radians)
        let height = ratio * rect.width / 2
        path.addLine(to: CGPoint(x: rect.midX, y: rect.midY - height))
        path.closeSubpath()

        // then create the circle
        let circle = Path(ellipseIn: CGRect(
            x: rect.midX - radius,
            y: rect.midY - radius,
            width: radius * 2,
            height: radius * 2
        ))
        return path.subtracting(circle)
    }
}

字符串
然后喙和身体可以这样组合:

var body: some View {
    ZStack {
        // MARK: Body
        Circle()
            .fill(.yellow)
            .overlay(alignment: .center) {
                Circle()
                    .stroke(lineWidth: 5)
            }
            .frame(width: 150)
        
        // MARK: Beak
        Beak(radius: 75, angle: .degrees(16))
            .stroke(style: .init(lineWidth: 5, lineJoin: .round))
            .padding(5)
        
    }
    .frame(width: 300, height: 300)
    .background(.orange)
}


备注:

  • 我把描边的圆放在填充的圆上面,这样更容易推断圆的描边在哪里,以及它有多粗,从而更容易对齐两条路径的描边。
  • 我使用.round线连接来处理喙,因为斜接连接看起来很糟糕
  • 我在鸟喙周围添加了一些填充,这样笔画就不会超出橙子背景。

输出量:


的数据

相关问题