【问题标题】:Masking CAGradientLayer over CALayers在 CALayers 上屏蔽 CAGradientLayer
【发布时间】:2017-08-17 15:45:21
【问题描述】:

在我的场景中,我有 2 个视图:第一个持有 CALayer 实例(条形),另一个持有 CAGradientLayer 并放置在第一个之上。下图描述了当前状态。

但我需要将此渐变仅应用于第一个视图的条形(CALayer)。

我没有找到任何与我的问题相关的信息。任何帮助表示赞赏。

【问题讨论】:

    标签: ios swift uikit calayer


    【解决方案1】:

    您必须对渐变应用蒙版。有多种方法可以解决这个问题。

    您可以创建一个CAShapeLayer,将形状层的path 设置为条形,并将渐变层的mask 设置为该形状层。

    或者您可以去掉条形层,而使用两个渐变层,一个用于橙色条,另一个用于灰色条。将两个渐变图层并排放置在子视图中,并将超级视图的图层蒙版设置为形状图层。以下是如何做到这一点。

    你需要两个渐变层和一个形状层:

    @IBDesignable
    class BarGraphView : UIView {
    
        private let orangeGradientLayer = CAGradientLayer()
        private let grayGradientLayer = CAGradientLayer()
        private let maskLayer = CAShapeLayer()
    

    您还需要条形宽度:

        private let barWidth = CGFloat(9)
    

    在初始化时,设置渐变并添加所有子层:

        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            commonInit()
        }
    
        private func commonInit() {
            backgroundColor = .black
    
            initGradientLayer(orangeGradientLayer, with: .orange)
            initGradientLayer(grayGradientLayer, with: .gray)
    
            maskLayer.strokeColor = nil
            maskLayer.fillColor = UIColor.white.cgColor
            layer.mask = maskLayer
        }
    
        private func initGradientLayer(_ gradientLayer: CAGradientLayer, with color: UIColor) {
            gradientLayer.colors = [ color, color, color.withAlphaComponent(0.6), color ].map({ $0.cgColor })
            gradientLayer.locations = [ 0.0, 0.5, 0.5, 1.0 ]
            layer.addSublayer(gradientLayer)
        }
    

    在布局时,设置渐变层的框架,设置遮罩层的路径。这需要一些工作,因为您不希望条形图是半橙色半灰色的。

        override func layoutSubviews() {
            super.layoutSubviews()
    
            let barCount = ceil(bounds.size.width / barWidth)
            let orangeBarCount = floor(barCount / 2)
            let grayBarCount = barCount - orangeBarCount
    
            var grayFrame = bounds
            grayFrame.size.width = grayBarCount * barWidth
            grayFrame.origin.x = frame.maxX - grayFrame.size.width
            grayGradientLayer.frame = grayFrame
    
            var orangeFrame = bounds
            orangeFrame.size.width -= grayFrame.size.width
            orangeGradientLayer.frame = orangeFrame
    
            maskLayer.frame = bounds
            maskLayer.path = barPath()
        }
    
        private func barPath() -> CGPath {
            var columnBounds = self.bounds
            columnBounds.origin.x = columnBounds.maxX
            columnBounds.size.width = barWidth
            let path = CGMutablePath()
            for datum in barData.reversed() {
                columnBounds.origin.x -= barWidth
                let barHeight = CGFloat(datum) * columnBounds.size.height
                let barRect = columnBounds.insetBy(dx: 1, dy: (columnBounds.size.height - barHeight) / 2)
                path.addRoundedRect(in: barRect, cornerWidth: 2, cornerHeight: 2)
            }
            return path
        }
    
        let barData: [Double] = {
            let count = 100
            return (0 ..< count).map({ 0.5 + (1 + sin(8.0 * .pi * Double($0) / Double(count))) / 4 })
        }()
    
    }
    

    结果:

    BarGraphView 在没有横条的地方都是透明的。如果您希望它在深色背景上,请在其后面放置一个深色视图,或使其成为深色视图的子视图:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-07
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多