SwiftUI 自定义圆角 RectangleShape

SwiftUI Custom Rounded RectangleShape

提问人:Westsider 提问时间:10/18/2023 最后编辑:Benzy NeezWestsider 更新时间:10/18/2023 访问量:41

问:

有谁知道如何制作这样的形状?enter image description here

我按照苹果教程提出了这个,但对于我想做的事情来说,它似乎过于复杂,而且并不完全圆润。对我来说,这似乎也很难实施和维护。似乎有一种更简单的方法。谢谢你的想法。

struct HexagonParameters {
    
    struct Segment {
        let line: CGPoint
        let curve: CGPoint
        let control: CGPoint
    }
    
    static let adjustment: CGFloat = 0.085
    
    static let topSholdHt = 0.13
    static let botSholdHt = 0.87
    
    static let segments = [
        
        Segment( // top center
                line:    CGPoint(x: 0.80, y: topSholdHt), // top right
                curve:   CGPoint(x: 0.20, y: topSholdHt), // top left
                control: CGPoint(x: 0.50, y: 0.00) // center / peak
            ),
            Segment( // upper left
                line:    CGPoint(x: 0.05, y: 0.20),
                curve:   CGPoint(x: 0.00, y: 0.30),
                control: CGPoint(x: 0.0, y: 0.23)
            ),
            Segment( // lower left
                line:    CGPoint(x: 0.00, y: 0.70),
                curve:   CGPoint(x: 0.05, y: 0.80),
                control: CGPoint(x: 0.00, y: 0.78)
            ),
            Segment( // bottom center
                line:    CGPoint(x: 0.20, y: botSholdHt),
                curve:   CGPoint(x: 0.80, y: botSholdHt),
                control: CGPoint(x: 0.50, y: 1.00)
            ),
            Segment(    // lower right
                line:    CGPoint(x: 0.95, y: 0.80),
                curve:   CGPoint(x: 1.00, y: 0.70),
                control: CGPoint(x: 1.00, y: 0.78)
            ),
            Segment(
                line:    CGPoint(x: 1.00, y: 0.30),
                curve:   CGPoint(x: 0.95, y: 0.20),
                control: CGPoint(x: 1.00, y: 0.23)
            )
    ]
    
}

结构是这样用的

struct ContentView: View {
    var body: some View {
        Path { path in
            var width: CGFloat = 300.0
            let height = width
            path.move(
                to: CGPoint(
                    x: width * 0.95,
                    y: height * 0.20
                )
            )
            
            HexagonParameters.segments.forEach { segment in
                path.addLine(
                    to: CGPoint(
                        x: width * segment.line.x,
                        y: height * segment.line.y
                    )
                )
                
                path.addQuadCurve(
                    to: CGPoint(
                        x: width * segment.curve.x,
                        y: height * segment.curve.y),
                    control: CGPoint(
                        x: width * segment.control.x,
                        y: height * segment.control.y
                    )
                )
            }
        }
        .stroke(style: StrokeStyle(lineWidth: 2))
        .foregroundColor(Color.black)
        .padding(.horizontal)

    }
}
SwiftUI 路径 绘制 形状

评论

0赞 Benzy Neez 10/18/2023
看起来你自己解决了,形状看起来很棒。您也可以创建自定义 ,但它可能是相似数量的代码,并且不会更简单。当你说它不是完美的圆角时,你实际上是想平滑角落,让它从角落扫到中间山峰,在角落附近没有倒弧吗?Shape

答:

1赞 Benzy Neez 10/18/2023 #1

正如我在评论中所说,看起来您自己解决了它,您的代码生成了问题中的形状。

但是,您说您的形状是:

不完美圆润

所以我想知道你是否在尝试实现一个更平滑的形状,在角落附近没有倒弧?

假设是这种情况,以下是如何解决它 自定义 .我不会说它比你原来的维护更简单,但至少它展示了一种不同的方法。Shape

struct Lozenge: Shape {
    func path(in rect: CGRect) -> Path {
        let cornerRadius = min(rect.size.width, rect.size.height) * 0.1
        let middleHeight = rect.size.height * 0.15
        let cornerAngleRadians = atan2(rect.size.width, rect.size.height - (2 * middleHeight))
        let cornerAngleDegrees = cornerAngleRadians * 180 / Double.pi

        var path = Path()
        var x = rect.minX
        var y = rect.minY + cornerRadius + middleHeight
        path.move(to: CGPoint(x: x, y: y))

        // Top-left corner
        x += cornerRadius
        path.addArc(
            center: CGPoint(x: x, y: y),
            radius: cornerRadius,
            startAngle: .degrees(-180),
            endAngle: .degrees(-180 + cornerAngleDegrees),
            clockwise: false
        )
        // Middle bump on top
        x = rect.maxX - cornerRadius + (cornerRadius * cos(cornerAngleRadians))
        y = rect.minY + middleHeight + cornerRadius - (cornerRadius * sin(cornerAngleRadians))
        path.addQuadCurve(
            to: CGPoint(x: x, y: y),
            control: CGPoint(x: rect.midX, y: rect.minY - middleHeight)
        )
        // Top-right corner
        x = rect.maxX - cornerRadius
        y = rect.minY + cornerRadius + middleHeight
        path.addArc(
            center: CGPoint(x: x, y: y),
            radius: cornerRadius,
            startAngle: .degrees(-cornerAngleDegrees),
            endAngle: .degrees(0),
            clockwise: false
        )
        // Bottom-right corner
        y = rect.maxY - cornerRadius - middleHeight
        path.addArc(
            center: CGPoint(x: x, y: y),
            radius: cornerRadius,
            startAngle: .degrees(0),
            endAngle: .degrees(cornerAngleDegrees),
            clockwise: false
        )
        // Lower bump on bottom
        x = rect.minX + cornerRadius - (cornerRadius * cos(cornerAngleRadians))
        y = rect.maxY - middleHeight - cornerRadius + (cornerRadius * sin(cornerAngleRadians))
        path.addQuadCurve(
            to: CGPoint(x: x, y: y),
            control: CGPoint(x: rect.midX, y: rect.maxY + middleHeight)
        )
        // Bottom-left corner
        x = rect.minX + cornerRadius
        y = rect.maxY - cornerRadius - middleHeight
        path.addArc(
            center: CGPoint(x: x, y: y),
            radius: cornerRadius,
            startAngle: .degrees(180 - cornerAngleDegrees),
            endAngle: .degrees(180),
            clockwise: false
        )
        path.closeSubpath()
        return path
    }
}

struct ContentView: View {
    var body: some View {
        Lozenge()
            .stroke(lineWidth: 3)
            .frame(width: 300, height: 250)
            .background(.yellow)
    }
}

Lozenge

评论

0赞 Westsider 10/18/2023
非常感谢。我试图弄清楚如何使用 addArc 做到这一点,但就是无法得到它。哇!我现在也能看到我哪里出了问题。
0赞 Westsider 10/18/2023
这是一个巨大的帮助 - 谢谢!!
0赞 Benzy Neez 10/18/2023
不客气😊 感谢您接受答案。
0赞 Benzy Neez 10/18/2023
@Westsider 将弧度转换为度数的公式中存在错误(使用 + 而不是 *)。现已更正。
0赞 Westsider 10/19/2023
啊 - 很棒的收获 - 比你!!