Files
VoidLink/VoidLink/Utility/GraphicUtils.swift
T
True Zhuanjia 0728e999eb - add necessary UI tips
- restore "view all apps" for host card
- minor fixes
2026-02-26 22:32:37 +08:00

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
}
}