在我的场景中,我有2个视图:第一个持有CALayer实例(条形图),另一个持有CAGradientLayer并放在第一个视图上。下图描述了当前状态。
但我需要将此渐变仅应用于第一个视图的条形图(CALayer)。
我还没有找到与我的问题相关的任何信息。任何帮助表示赞赏。
答案 0 :(得分:5)
您必须将遮罩应用于渐变。有多种方法可以解决这个问题。
您可以创建CAShapeLayer
,将形状图层的path
设置为条形,然后将渐变图层的mask
设置为该形状图层。
或者你可以摆脱条形图层,而是使用两个渐变层,一个用于橙色条,另一个用于灰色条。将两个渐变图层并排放置在子视图中,并将superview的图层蒙版设置为形状图层。这是如何做到的。
您需要两个渐变图层和一个形状图层:
@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
就是透明的。如果你想要它在黑暗的背景下,在它背后放一个黑暗的视图,或使它成为黑暗视图的子视图: