如何将figma径向渐变导出到CAGradientLayer

问题描述 投票:0回答:1

Figma gradient

CSS 带有鼓舞人心的评论

background: radial-gradient(423.17% 112.48% at 32.67% 115.21%, #FFD3D3 7.4%, #E7B9B9 24.14%, #596EBB 58.01%, #382A8B 96.1%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */; 

导出屏幕时 svg 的相关部分:

这产生了令人厌恶的代码,其起点和终点是我从墙上摘下来的:

static func shouldMakeGradientLayer(frame: CGRect? = nil) -> CAGradientLayer {
        
        let gradientLayer = CAGradientLayer()

        // Define colors
        gradientLayer.colors = [
            UIColor(hex: 0xFFD3D3).cgColor,
            UIColor(hex: 0xE7B9B9).cgColor,
            UIColor(hex: 0x596EBB).cgColor,
            UIColor(hex: 0x382A8B).cgColor
        ].reversed()

        // Define locations
        //background: radial-gradient(423.17% 112.48% at 32.67% 115.21%, #FFD3D3 7.4%, #E7B9B9 24.14%, #596EBB 58.01%, #382A8B 96.1%) /* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */;
//      gradientLayer.locations = [0.0739577, 0.241399, 0.580144, 0.961]
//  make a guess :-[    gradientLayer.locations = [0, 0.8, 0.9, 1

        // Apply the gradient transform
        gradientLayer.type = .radial
//      let transform = CATransform3DMakeRotation(-71.2512 * (.pi / 180), 0, 0, 1)
        guard let w = frame?.width, let h = frame?.height else {
            return gradientLayer
        }
//      gradientLayer.transform = CATransform3DConcat(CATransform3DMakeScale(964.534/w, 1675.8/w, 1), transform)
//      gradientLayer.position = CGPoint(x: 122.5, y: 935.5)

        gradientLayer.transform = CATransform3DMakeScale(964.534/w, 1675.8/h, 1)

        let startPoint: CGPoint = CGPoint(x: 1, y: 0)
        let endPoint: CGPoint = CGPoint(x: -2.2, y: 1.4)
        gradientLayer.startPoint = startPoint
        gradientLayer.endPoint = endPoint
        if let frame = frame {
            gradientLayer.frame = frame
        }
        return gradientLayer
    }

问题#1:有没有更简单的方法来获得径向渐变? 或者 问题#2:我是否应该让 UI 设计师隔离我需要作为背景的 svg 部分,然后硬着头皮在每个需要它的 uiviewcontroller(30+ 屏幕)中添加 UIImageView 作为背景?

也许有一些直接的方法可以将 CSS 百分比映射到位置数组?

UPD:Youtube 及时向我推荐 https://www.youtube.com/watch?v=I4gUvhG7uFU 让我少讨厌 css 一点。但免责声明仍然有效,我不懂 css,可以在这里求助。

uikit core-graphics cagradientlayer
1个回答
0
投票

指定径向渐变方向的枚举

enum RadialGradientDirection {
    case centerToEdge
    case edgeToCenter
}

扩展 UIView 以添加径向渐变功能

extension UIView {
    func applyRadialGradient(colors: [UIColor], direction: RadialGradientDirection, radius: CGFloat? = nil) {
        let gradientLayer = RadialGradientLayer()
        
        gradientLayer.colors = colors.map { $0.cgColor }
        
        // Define the center and the radius for the gradient
        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let endRadius = radius ?? max(bounds.width, bounds.height) / 2
        
        switch direction {
        case .centerToEdge:
            gradientLayer.startCenter = center
            gradientLayer.endCenter = center
            gradientLayer.startRadius = 0
            gradientLayer.endRadius = endRadius
            
        case .edgeToCenter:
            gradientLayer.startCenter = center
            gradientLayer.endCenter = center
            gradientLayer.startRadius = endRadius
            gradientLayer.endRadius = 0
        }
        
        gradientLayer.frame = self.bounds
        
        self.layer.insertSublayer(gradientLayer, at: 0)
    }
    
    func removeRadialGradient() {
        layer.sublayers?
            .filter { $0 is RadialGradientLayer } // Find all radial gradient layers
            .forEach { $0.removeFromSuperlayer() } // Remove them
    }
}

自定义径向渐变层

class RadialGradientLayer: CALayer {
    var colors: [CGColor] = []
    var startCenter: CGPoint = .zero
    var endCenter: CGPoint = .zero
    var startRadius: CGFloat = 0
    var endRadius: CGFloat = 0
    
    override func draw(in ctx: CGContext) {
        ctx.saveGState()
        
        // Create a gradient with the provided colors
        guard let gradient = CGGradient(colorsSpace: nil, colors: colors as CFArray, locations: nil) else { return }
        
        // Draw the radial gradient
        ctx.drawRadialGradient(
            gradient,
            startCenter: startCenter,
            startRadius: startRadius,
            endCenter: endCenter,
            endRadius: endRadius,
            options: .drawsBeforeStartLocation
        )
        
        ctx.restoreGState()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.