简体   繁体   中英

Highlighter: How to use CALayer to adjust superview's alpha like a highlighter

在此处输入图像描述

These buttons represent sets, each set can be...

Empty: "K7s" is empty and represented by K7s.alpha = 0.4

Full: "Q7s" is full and represented by Q7s.alpha = 1.0 & borderWidth = 2

or

Partially Filled: "J7s" is a partially filled set, represented by adding the smaller frame. I'd like this smaller frame to be a CALayer that adjusts the SuperLayer(J7s)'s alpha to 1.0 inside the new layer's bounds. The result would appear as...

在此处输入图像描述

let highlighterLayer = CALayer()
highlighterLayer.borderWidth = 1
highlighterLayer.bounds = CGRect(x: 0, y: 0, width: buttonSize.width, height: percentHeight)
Buttons[tag].layer.addSublayer(highlighterLayer)
highlighterLayer.position = CGPoint(x: Buttons[tag].bounds.midX, y: Buttons[tag].bounds.midY)
Highlights[tag] = highlighterLayer 

We cannot do something with a sublayer that will "adjust" the superlayer's alpha.

However, you can add a sublayer and change its alpha and border width.

Quick example -- UIButton subclass:

class SomeButton: UIButton {
    public var fillPct: CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }
    public var highlightColor: UIColor = .green
    
    private let highlighterLayer = CALayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        highlighterLayer.borderColor = UIColor.black.cgColor
        layer.addSublayer(highlighterLayer)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        var r = bounds
        r.size.height *= fillPct
        highlighterLayer.frame = r
        highlighterLayer.position = CGPoint(x: bounds.midX, y: bounds.midY)
        highlighterLayer.borderWidth = 2.0 * fillPct
        highlighterLayer.backgroundColor = highlightColor.withAlphaComponent(fillPct).cgColor
    }
}

and a demo controller - each tap of the "Cycle Values" button will cycle through a few sets of example "fill percentage" values:

class HighlightButtonTestVC: UIViewController {
    
    var btns: [SomeButton] = []
    
    var demoVals: [[CGFloat]] = [
        [0.0, 1.0, 0.5],
        [1.0, 0.5, 0.0],
        [0.5, 0.5, 1.0],
    ]
    var valsIdx: Int = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let stackView = UIStackView()
        stackView.backgroundColor = UIColor(red: 0.0, green: 0.4, blue: 0.0, alpha: 1.0)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stackView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            stackView.heightAnchor.constraint(equalToConstant: 60.0),
            stackView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
        ])
        
        ["K7s", "Q7s", "J7s"].forEach { str in
            let b = SomeButton()
            b.setTitle(str, for: [])
            b.setTitleColor(.black, for: .normal)
            b.setTitleColor(.lightGray, for: .highlighted)
            stackView.addArrangedSubview(b)
            btns.append(b)
        }
        for i in 0..<3 {
            btns[i].fillPct = demoVals[0][i]
        }
        
        let vBtn = UIButton(type: .system)
        vBtn.setTitle("Cycle Values", for: [])
        vBtn.addTarget(self, action: #selector(cycleVals), for: .touchUpInside)
        vBtn.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(vBtn)
        NSLayoutConstraint.activate([
            vBtn.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 20.0),
            vBtn.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            vBtn.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
        ])
    }
    
    @objc func cycleVals() {
        valsIdx += 1
        for i in 0..<3 {
            btns[i].fillPct = demoVals[valsIdx % 3][i]
        }
    }

}

The result - for value sets:

[0.0, 1.0, 0.5],
[1.0, 0.5, 0.0],
[0.5, 0.5, 1.0],

is:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM