141 lines
4.2 KiB
Swift
141 lines
4.2 KiB
Swift
//
|
|
// GraphicUtils.swift
|
|
// VoidLink
|
|
//
|
|
// Created by True砖家 on 2025/12/24.
|
|
// Copyright © 2025 True砖家@Bilibili. All rights reserved.
|
|
//
|
|
|
|
|
|
import Foundation
|
|
import SVGKit
|
|
|
|
@objc public class GraphicUtils: NSObject {
|
|
@objc public static func makeSVGLayer(
|
|
from file: String,
|
|
in container: CALayer,
|
|
at normalizedPosition: CGPoint = .zero,
|
|
targetSize: CGSize
|
|
) -> CALayer {
|
|
|
|
guard let url = Bundle.main.url(forResource: file, withExtension: "svg"),
|
|
let data = try? Data(contentsOf: url) else {
|
|
return CALayer()
|
|
}
|
|
|
|
guard let svg = SVGKImage(data: data) else {
|
|
fatalError("Failed to load SVG \(file)")
|
|
}
|
|
|
|
return _makeSVGLayer(
|
|
from: svg,
|
|
in: container,
|
|
at: normalizedPosition,
|
|
targetSize: targetSize
|
|
)
|
|
}
|
|
|
|
public static func makeCenteredSVGLayer(
|
|
from svg: SVGKImage,
|
|
in container: CALayer,
|
|
targetSize: CGSize
|
|
) -> CALayer {
|
|
return _makeSVGLayer(
|
|
from: svg,
|
|
in: container,
|
|
targetSize: targetSize
|
|
)
|
|
}
|
|
|
|
@objc public static func _makeSVGLayer(
|
|
from svg: SVGKImage,
|
|
in container: CALayer,
|
|
at normalizedPosition: CGPoint = .zero,
|
|
targetSize: CGSize,
|
|
getWrapperLayer: Bool = true
|
|
) -> CALayer {
|
|
|
|
let svgLayer = svg.caLayerTree!
|
|
|
|
svgLayer.transform = CATransform3DIdentity
|
|
|
|
var unionRect = CGRect.null
|
|
func accumulateBounds(_ layer: CALayer) {
|
|
unionRect = unionRect.union(layer.frame)
|
|
layer.sublayers?.forEach { accumulateBounds($0) }
|
|
}
|
|
accumulateBounds(svgLayer)
|
|
|
|
svgLayer.setAffineTransform(
|
|
CGAffineTransform(
|
|
translationX: -unionRect.origin.x,
|
|
y: -unionRect.origin.y
|
|
)
|
|
)
|
|
|
|
let realPosition = (normalizedPosition == .zero
|
|
? CGPoint(x: container.bounds.midX,y: container.bounds.midY)
|
|
: CGPoint(x: container.bounds.width*normalizedPosition.x,y: container.bounds.height*normalizedPosition.y))
|
|
|
|
let wrapper = CALayer()
|
|
wrapper.bounds = CGRect(origin: .zero, size: unionRect.size)
|
|
wrapper.anchorPoint = CGPoint(x: 0.5, y: 0.5)
|
|
wrapper.position = realPosition
|
|
|
|
let scale = min(
|
|
targetSize.width / unionRect.width,
|
|
targetSize.height / unionRect.height
|
|
)
|
|
|
|
wrapper.setAffineTransform(
|
|
CGAffineTransform(scaleX: scale, y: scale)
|
|
)
|
|
|
|
wrapper.addSublayer(svgLayer)
|
|
|
|
if !getWrapperLayer {
|
|
return wrapper
|
|
}
|
|
|
|
let wrappedLayer = CALayer()
|
|
wrappedLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
|
|
wrappedLayer.bounds = CGRect(x: 0, y: 0, width: container.bounds.size.width, height: container.bounds.size.height)
|
|
wrappedLayer.position = CGPoint(x: container.bounds.midX, y: container.bounds.midY)
|
|
wrappedLayer.insertSublayer(wrapper, at: 0)
|
|
|
|
return wrappedLayer
|
|
}
|
|
|
|
@objc public static func changeColor(layer: CALayer, color: UIColor) {
|
|
if let shape = layer as? CAShapeLayer {
|
|
shape.fillColor = color.cgColor
|
|
shape.strokeColor = color.cgColor
|
|
}
|
|
layer.sublayers?.forEach { changeColor(layer: $0, color: color) }
|
|
}
|
|
|
|
@objc public static func makeTouchTrackpoint(in view:UIView) -> CAShapeLayer {
|
|
var trackPoint = CAShapeLayer()
|
|
let path = UIBezierPath(
|
|
arcCenter: CGPoint(x: 0, y: 0),
|
|
radius: GenericUtils.isIPhone() ? 12 : 15,
|
|
startAngle: 0,
|
|
endAngle: CGFloat.pi * 2,
|
|
clockwise: true
|
|
)
|
|
|
|
trackPoint = CAShapeLayer()
|
|
trackPoint.path = path.cgPath
|
|
|
|
trackPoint.fillColor = UIColor.white.withAlphaComponent(0.3).cgColor
|
|
trackPoint.strokeColor = UIColor.clear.cgColor
|
|
trackPoint.lineWidth = 0
|
|
|
|
view.layer.addSublayer(trackPoint)
|
|
trackPoint.position = view.center
|
|
trackPoint.isHidden = true
|
|
|
|
return trackPoint
|
|
}
|
|
}
|