148 lines
4.6 KiB
Swift
148 lines
4.6 KiB
Swift
import SwiftUI
|
||
import SVGKit
|
||
|
||
struct SVGImage: UIViewRepresentable {
|
||
let svgName: String
|
||
var contentMode: ContentMode = .fit
|
||
var tintColor: Color?
|
||
|
||
private var svgPath: String {
|
||
return svgName
|
||
}
|
||
|
||
private func createImageView() -> SVGKFastImageView {
|
||
let emptySVGString = """
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet">
|
||
<rect width="1" height="1" fill="transparent"/>
|
||
</svg>
|
||
"""
|
||
|
||
if let data = emptySVGString.data(using: .utf8),
|
||
let svgImage = SVGKImage(data: data) {
|
||
let imageView = SVGKFastImageView(svgkImage: svgImage) ?? SVGKFastImageView()
|
||
imageView.contentMode = .scaleAspectFit
|
||
imageView.backgroundColor = .clear
|
||
return imageView
|
||
}
|
||
|
||
let fallbackView = SVGKFastImageView()
|
||
fallbackView.backgroundColor = .clear
|
||
return fallbackView
|
||
}
|
||
|
||
func makeUIView(context: Context) -> SVGKFastImageView {
|
||
print("🔄 开始加载SVG: \(svgName)")
|
||
let imageView = createImageView()
|
||
loadSVG(into: imageView)
|
||
configureView(imageView)
|
||
return imageView
|
||
}
|
||
|
||
private func loadSVG(into imageView: SVGKFastImageView) {
|
||
guard let path = Bundle.main.path(forResource: svgPath, ofType: "svg") else {
|
||
print("⚠️ 在main bundle中找不到文件: \(svgPath).svg")
|
||
return
|
||
}
|
||
|
||
let url = URL(fileURLWithPath: path)
|
||
guard let svgImage = SVGKImage(contentsOf: url) else {
|
||
print("❌ 无法从URL创建SVG: \(path)")
|
||
return
|
||
}
|
||
|
||
// 设置SVG的尺寸为容器大小
|
||
let containerSize = imageView.bounds.size
|
||
if containerSize != .zero {
|
||
svgImage.size = containerSize
|
||
} else {
|
||
// 如果容器大小未知,设置一个默认大小
|
||
svgImage.size = CGSize(width: 100, height: 100)
|
||
}
|
||
|
||
print("✅ 成功加载SVG: \(svgName), 尺寸: \(svgImage.size)")
|
||
|
||
DispatchQueue.main.async {
|
||
imageView.image = svgImage
|
||
imageView.setNeedsLayout()
|
||
imageView.layoutIfNeeded()
|
||
}
|
||
}
|
||
|
||
private func configureView(_ imageView: SVGKFastImageView) {
|
||
imageView.contentMode = contentMode == .fit ? .scaleAspectFit : .scaleAspectFill
|
||
imageView.clipsToBounds = true
|
||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||
imageView.backgroundColor = .clear
|
||
|
||
// 确保图片视图可以正确缩放
|
||
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||
|
||
if let tintColor = tintColor?.uiColor {
|
||
imageView.tintColor = tintColor
|
||
DispatchQueue.main.async {
|
||
self.applyTintColor(tintColor, to: imageView.layer)
|
||
}
|
||
}
|
||
}
|
||
|
||
private func applyTintColor(_ color: UIColor, to layer: CALayer) {
|
||
if let shapeLayer = layer as? CAShapeLayer {
|
||
shapeLayer.fillColor = color.cgColor
|
||
}
|
||
|
||
layer.sublayers?.forEach { sublayer in
|
||
applyTintColor(color, to: sublayer)
|
||
}
|
||
}
|
||
|
||
func updateUIView(_ uiView: SVGKFastImageView, context: Context) {
|
||
loadSVG(into: uiView)
|
||
|
||
if let tintColor = tintColor?.uiColor {
|
||
uiView.tintColor = tintColor
|
||
DispatchQueue.main.async {
|
||
self.applyTintColor(tintColor, to: uiView.layer)
|
||
}
|
||
}
|
||
|
||
uiView.contentMode = contentMode == .fit ? .scaleAspectFit : .scaleAspectFill
|
||
}
|
||
|
||
func sizeThatFits(_ proposal: ProposedViewSize, uiView: SVGKFastImageView, context: Context) -> CGSize? {
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// MARK: - ContentMode
|
||
extension SVGImage {
|
||
enum ContentMode {
|
||
case fit // 保持宽高比,适应容器
|
||
case fill // 保持宽高比,填充容器(可能被裁剪)
|
||
}
|
||
}
|
||
|
||
// MARK: - Preview
|
||
#Preview {
|
||
VStack(spacing: 20) {
|
||
Text("IP SVG")
|
||
SVGImage(svgName: "IP")
|
||
.frame(width: 100, height: 100)
|
||
.background(Color.gray.opacity(0.2))
|
||
.border(Color.red, width: 1)
|
||
|
||
Text("Pioneer SVG")
|
||
SVGImage(svgName: "Pioneer", contentMode: .fill)
|
||
.frame(width: 100, height: 50)
|
||
.background(Color.gray.opacity(0.2))
|
||
.border(Color.blue, width: 1)
|
||
.clipped()
|
||
}
|
||
.padding()
|
||
}
|
||
|
||
// MARK: - Color Extension
|
||
private extension Color {
|
||
var uiColor: UIColor {
|
||
return UIColor(self)
|
||
}
|
||
} |