You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从SwiftUI的Image中获取Path对象?

如何将SF Symbols系统图标转为Shape可用的Path?

你的代码思路方向是对的,但SwiftUI的Image并没有path(in:)方法,没法直接从Image对象获取路径。要实现把SF Symbols系统图标转为Shape可用的Path,需要借助UIKit的UIImage来提取图标的矢量轮廓,具体实现如下:

完整实现代码

import SwiftUI

// 保留你自定义的DrawInfo结构体,可根据需求调整属性
struct DrawInfo {
    var iconSize: CGFloat
}

struct SystemIconShape: Shape {
    var drawInfo: DrawInfo
    var iconName: String

    init(_ drawInfo: DrawInfo, _ iconName: String) {
        self.drawInfo = drawInfo
        self.iconName = iconName
    }

    func path(in rect: CGRect) -> Path {
        // 加载SF Symbols图标,配置尺寸适配当前矩形
        let config = UIImage.SymbolConfiguration(pointSize: min(rect.width, rect.height))
        guard let uiImage = UIImage(systemName: iconName, withConfiguration: config) else {
            return Path() // 图标加载失败时返回空路径
        }

        // 将UIImage转为CGPath
        guard let cgPath = uiImage.cgPath(in: rect) else {
            return Path()
        }

        return Path(cgPath)
    }
}

// 给UIImage添加扩展,提取SF Symbols的矢量路径
extension UIImage {
    func cgPath(in rect: CGRect) -> CGPath? {
        // 创建矢量渲染上下文
        let renderer = UIGraphicsImageRenderer(size: rect.size)
        let image = renderer.image { context in
            self.draw(in: rect)
        }

        guard let cgImage = image.cgImage else { return nil }
        let ciImage = CIImage(cgImage: cgImage)

        // 使用CoreImage滤镜提取图标轮廓
        let edgeFilter = CIFilter(name: "CIColorEdges")!
        edgeFilter.setValue(ciImage, forKey: kCIInputImageKey)
        edgeFilter.setValue(1.0, forKey: kCIInputIntensityKey)

        guard let edgeImage = edgeFilter.outputImage else { return nil }
        let ciContext = CIContext()

        guard let edgeCGImage = ciContext.createCGImage(edgeImage, from: edgeImage.extent) else { return nil }

        // 通过位图分析生成路径
        let width = edgeCGImage.width
        let height = edgeCGImage.height
        let bytesPerRow = width * 4

        guard let context = CGContext(data: nil,
                                      width: width,
                                      height: height,
                                      bitsPerComponent: 8,
                                      bytesPerRow: bytesPerRow,
                                      space: CGColorSpaceCreateDeviceRGB(),
                                      bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
            return nil
        }

        context.draw(edgeCGImage, in: CGRect(x: 0, y: 0, width: width, height: height))
        guard let data = context.data else { return nil }

        let pixels = data.bindMemory(to: UInt32.self, capacity: width * height)
        var path = Path()
        var isTrackingPath = false

        // 扫描像素点生成轮廓路径
        for y in 0..<height {
            for x in 0..<width {
                let pixel = pixels[y * width + x]
                let alpha = CGFloat((pixel >> 24) & 0xFF) / 255.0

                if alpha > 0.5 {
                    let pointX = CGFloat(x) / CGFloat(width) * rect.width + rect.minX
                    let pointY = CGFloat(height - y) / CGFloat(height) * rect.height + rect.minY
                    let point = CGPoint(x: pointX, y: pointY)

                    if !isTrackingPath {
                        path.move(to: point)
                        isTrackingPath = true
                    } else {
                        path.addLine(to: point)
                    }
                } else {
                    isTrackingPath = false
                }
            }
            isTrackingPath = false
        }

        return path.cgPath
    }
}

// 使用示例
struct IconShapeDemoView: View {
    var body: some View {
        SystemIconShape(DrawInfo(iconSize: 24), "heart.fill")
            .fill(Color.red)
            .frame(width: 100, height: 100)
    }
}

关键说明

  1. 图标加载:通过UIImage(systemName:withConfiguration:)加载SF Symbols图标,配置尺寸适配目标矩形,保证图标在Shape内显示正常。
  2. 路径提取:先用CoreImage边缘检测滤镜提取图标轮廓,再通过像素扫描生成CGPath,最后转为SwiftUI的Path。
  3. 错误处理:添加了图标加载失败、路径生成失败时的空路径返回逻辑,避免运行时崩溃。

内容的提问来源于stack exchange,提问作者Keith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 09:47:03