如何创建 SwiftUI RoundedStar 形状?

Posted

技术标签:

【中文标题】如何创建 SwiftUI RoundedStar 形状?【英文标题】:How to Create a SwiftUI RoundedStar Shape? 【发布时间】:2020-08-29 18:04:17 【问题描述】:

这是一个自我回答的问题,在 Stack Overflow 上完全可以接受(甚至鼓励)。重点是分享一些对他人有用的东西。

SwiftUI 有一个 RoundedRectangle Shape。最好有一个五角星形,尖端圆润,可用于填充、剪切和动画。

此Stack Overflow answer 展示了如何使用UIBezierPathRoundedStar 作为自定义UIView

如何将这段代码改编为SwiftUI作为可以动画的Shape

【问题讨论】:

【参考方案1】:

这是改编为动画 SwiftUI 的 RoundedStar 代码Shape

// Five-point star with rounded tips
struct RoundedStar: Shape 
    var cornerRadius: CGFloat
    
    var animatableData: CGFloat 
        get  return cornerRadius 
        set  cornerRadius = newValue 
    
    
    func path(in rect: CGRect) -> Path 
        var path = Path()
        let center = CGPoint(x: rect.width / 2, y: rect.height / 2)
        let r = rect.width / 2
        let rc = cornerRadius
        let rn = r * 0.95 - rc
        
        // start angle at -18 degrees so that it points up
        var cangle = -18.0
        
        for i in 1 ... 5 
            // compute center point of tip arc
            let cc = CGPoint(x: center.x + rn * CGFloat(cos(Angle(degrees: cangle).radians)), y: center.y + rn * CGFloat(sin(Angle(degrees: cangle).radians)))

            // compute tangent point along tip arc
            let p = CGPoint(x: cc.x + rc * CGFloat(cos(Angle(degrees: cangle - 72).radians)), y: cc.y + rc * CGFloat(sin(Angle(degrees: (cangle - 72)).radians)))

            if i == 1 
                path.move(to: p)
             else 
                path.addLine(to: p)
            

            // add 144 degree arc to draw the corner
            path.addArc(center: cc, radius: rc, startAngle: Angle(degrees: cangle - 72), endAngle: Angle(degrees: cangle + 72), clockwise: false)

            // Move 144 degrees to the next point in the star
            cangle += 144
        

        return path
    

代码与UIBezierPath 版本非常相似,只是它使用了新的Angle 类型,可以轻松访问degreesradians。移除了绘制旋转星形的代码,因为使用 .rotationEffect(angle:) 视图修饰符很容易为 SwiftUI 形状添加旋转。


演示:

这是一个演示,展示了cornerRadius 设置的动画品质,以及各种cornerRadius 设置在全屏星星上的样子。

struct ContentView: View 
    @State private var radius: CGFloat = 0.0
    
    var body: some View 
        ZStack 
            Color.blue.edgesIgnoringSafeArea(.all)
            VStack(spacing: 40) 
                Spacer()
                RoundedStar(cornerRadius: radius)
                    .aspectRatio(1, contentMode: .fit)
                    .foregroundColor(.yellow)
                    .overlay(Text("     cornerRadius: \(Int(self.radius))     ").font(.body))
                HStack 
                    ForEach([0, 10, 20, 40, 80, 200], id: \.self)  value in
                        Button(String(value)) 
                            withAnimation(.easeInOut(duration: 0.3)) 
                                self.radius = CGFloat(value)
                            
                        
                        .frame(width: 50, height: 50)
                        .foregroundColor(.black)
                        .background(Color.yellow.cornerRadius(8))
                    
                
                Spacer()
            
        
    


在 iPad 上的 Swift Playgrounds 中跑步

这可以在 iPad 上的 Swift Playgrounds 应用程序中完美运行。只需添加:

import PlaygroundSupport

在顶部和

PlaygroundPage.current.setLiveView(ContentView())

在最后。


使用 RoundedStar 形状创建欧盟标志

struct ContentView: View 
    let radius: CGFloat = 100
    let starWidth: CGFloat = 36
    let numStars = 12
    
    var body: some View 
        ZStack 
            Color.blue
            ForEach(0..<numStars)  n in
                RoundedStar(cornerRadius: 0)
                    .frame(width: starWidth, height: starWidth)
                    .offset(x: radius * cos(CGFloat(n) / CGFloat(numStars) * 2 * .pi), y: radius * sin(CGFloat(n) / CGFloat(numStars) * 2 * .pi))
                    .foregroundColor(.yellow)
            
        
    

【讨论】:

以上是关于如何创建 SwiftUI RoundedStar 形状?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 swiftui 创建表情符号键盘?

如何在 SwiftUI 中为列表创建标题?

如何使用 SwiftUI 创建具有 alpha 值的颜色?

如何在 SwiftUI 中为 NavigationLink 创建工厂方法?

如何在 SwiftUI 中使用 Firestore 创建子集合

如何在 SwiftUI 上创建一个空的“视图”数组?