SwiftUI - 如何组合两个形状以创建带​​有笔划的语音气泡

Cha*_*hal 1 xcode swift swiftui

我正在尝试重新创建 Duolingo 在其应用程序中使用的形状样式:

但由于笔画重叠,我一直在尝试组合两个形状:

这是我当前的代码:

HStack{
  Rectangle()
            .fill(Color.white)
            .frame(width: 20, height: 20, alignment: .center)

            .overlay(
                RoundedRectangle(cornerRadius: 6)

                    .stroke(Color.gray, lineWidth: 3)
            )
            .rotationEffect(Angle(degrees: 45))
            .offset(x: 18, y: 15)

        VStack(alignment: .leading, spacing: 0, content: {
            // MARK: USER NAME

            //                Text(comment.username)
            //                    .font(.caption)
            //                    .foregroundColor(.gray)

            // MARK: CONTENT

            Text(comment.content)
                .padding(.all, 10)
                .foregroundColor(.primary)
                .background(Color.white)

        })
            .background(Color.primary)
            .frame(width: .infinity)
            .frame(maxWidth: .infinity, minHeight: 50)
            .overlay(
                RoundedRectangle(cornerRadius: 16)
                    .stroke(Color.gray, lineWidth: 3)
                    .frame(maxWidth: .infinity - 50, minHeight: 50)
            )
Run Code Online (Sandbox Code Playgroud)

}

有任何想法吗?

谢谢!!

Geo*_*e_E 9

您可以使用Shape它来实现此目的。

例子:

struct SpeechBubble: Shape {
    private let radius: CGFloat
    private let tailSize: CGFloat

    init(radius: CGFloat = 10) {
        self.radius = radius
        tailSize = 20
    }

    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: CGPoint(x: rect.minX, y: rect.maxY - radius))
            path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY - rect.height / 2))
            path.addCurve(
                to: CGPoint(x: rect.minX, y: rect.maxY - rect.height / 2 - tailSize),
                control1: CGPoint(x: rect.minX - tailSize, y: rect.maxY - rect.height / 2),
                control2: CGPoint(x: rect.minX, y: rect.maxY - rect.height / 2 - tailSize / 2)
            )
            path.addArc(
                center: CGPoint(x: rect.minX + radius, y: rect.minY + radius),
                radius: radius,
                startAngle: Angle(degrees: 180),
                endAngle: Angle(degrees: 270),
                clockwise: false
            )
            path.addArc(
                center: CGPoint(x: rect.maxX - radius, y: rect.minY + radius),
                radius: radius,
                startAngle: Angle(degrees: 270),
                endAngle: Angle(degrees: 0),
                clockwise: false
            )
            path.addArc(
                center: CGPoint(x: rect.maxX - radius, y: rect.maxY - radius),
                radius: radius,
                startAngle: Angle(degrees: 0),
                endAngle: Angle(degrees: 90),
                clockwise: false
            )
            path.addArc(
                center: CGPoint(x: rect.minX + radius, y: rect.maxY - radius),
                radius: radius,
                startAngle: Angle(degrees: 90),
                endAngle: Angle(degrees: 180),
                clockwise: false
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
struct ContentView: View {
    var body: some View {
        SpeechBubble()
            .stroke(Color.gray, lineWidth: 3)
            .frame(width: 300, height: 80)
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

结果

您还可以添加Text以下内容:

ZStack {
    SpeechBubble()
        .stroke(Color.gray, lineWidth: 3)

    Text("Some really long text in the speech bubble over multiple lines.").padding(10)
}
.frame(width: 300, height: 70)
Run Code Online (Sandbox Code Playgroud)