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

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

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

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

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

【问题讨论】:

    标签: swift animation swiftui shapes


    【解决方案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)
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-10
      • 1970-01-01
      • 2015-08-02
      • 1970-01-01
      • 1970-01-01
      • 2013-10-08
      • 2016-10-21
      相关资源
      最近更新 更多