如何使用 SwiftUI 在我的圆段中插入 UIImages?

问题描述

我在 SwiftUI 中制作了一个有 7 个段的圆/轮,现在我想在每个段中(在段的中心)插入图像(它们在一个数组中),我该怎么做?

enter image description here

代码

struct WheelShape: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        
        let pieSections = 7
        let linewidth: CGFloat = 0.0
        
        let smaller = rect.insetBy(dx: linewidth / 2.0,dy: linewidth / 2.0)
        let radius = smaller.width / 2.0

        let segmentAngle = 2.0 / CGFloat(pieSections) * CGFloat(Double.pi)
        
        let imageArray: [UIImage] = [
            UIImage(systemName: "house.fill")!,UIImage(systemName: "paintpalette.fill")!,UIImage(systemName: "airplane")!,UIImage(systemName: "cloud.fill")!,UIImage(systemName: "dollarsign.circle.fill")!,UIImage(systemName: "book.fill")!,UIImage(systemName: "bicycle")!
        ]
        
        // Draw segment dividers
        for index in 1...pieSections {
            let drawAngle = segmentAngle * CGFloat(index) + (360 / 7 / 2 * π / 180)
            let x = radius * cos(drawAngle) + rect.width / 2.0
            let y = radius * sin(drawAngle) + rect.height / 2.0
            let cgpoint = CGPoint(x: rect.width / 2,y: rect.height / 2)
            path.move(to: cgpoint)
            let cgPointLine = CGPoint(x: x,y: y)
            path.addLine(to: cgPointLine)
        }
        
        return path
    }
}


解决方法

这是一种将圆圈置于背景中并将 SF 符号置于叠加层中的方法。

WWDC 2019 的演示文稿展示了带有动画的楔形环。这是来源: Building Custom Views in SwiftUI

struct ContentView: View {
    let symbols = ["house.fill","paintpalette.fill","airplane","cloud.fill","dollarsign.circle.fill","book.fill","bicycle"]
    
    var body: some View {
        WheelShape(symbols)
            .stroke(
                Color(.blue),lineWidth: 3.0)
            .background(
                Circle().stroke(Color(.blue),lineWidth: 6.0))
            .overlay(
                annotations.foregroundColor(.purple))
    }
    
    var annotations : some View {
        ZStack {
            let theta = CGFloat(2) * .pi / CGFloat(symbols.count)
            GeometryReader { geo in
                let center = CGPoint(x: geo.size.width / 2,y: geo.size.height / 2)
                let radius = min(geo.size.width / 2,geo.size.height / 2) / 1.5
                ForEach(0..<symbols.count,id: \.self) { index in
                    let offset = theta * CGFloat(index) + theta / 2
                    // place SF Symbol,offset to center,then the radius
                    Image(systemName: symbols[index])
                        .offset(x: center.x,y: center.y)
                        .offset(x: radius * cos(offset),y: radius * sin(offset))
                        .frame(alignment: .center)
                        .offset(x: -10,y: -10) // fudge factor to center symbol in wedge
                }
            }
        }
    }

    struct WheelShape: Shape {
        let symbols : [String]
        
        init(_ symbols: [String]) {
            self.symbols = symbols
        }
        
        func path(in rect: CGRect) -> Path {
            // center of the shape we are drawing in
            let center = CGPoint(x: rect.size.width / 2,y: rect.size.height / 2)
            let radius = min(rect.size.width / 2,rect.size.height / 2)
            // each angle offset in radians
            let theta = CGFloat(2) * .pi / CGFloat(symbols.count)
            var path = Path()
            
            // enumerate the array so index is available
            symbols.enumerated().forEach({ (index,symbol) in
                let offset = theta * CGFloat(index)
                path.move(to: center)
                path.addLine(to: CGPoint(x: radius * cos(offset) + center.x,y: radius * sin(offset) + center.y))
            })
            
            return path
        }
    }
}

Symbols centered in wedge