I have an image in my iPad app and I basically want to place a color filter on top of it. For this I have a colored UIView that is masked to a certain shape that I put over the
iOS 13, Swift 5
The key is setting the compositingFilter
property on the appropriate CALayer (the one on top - it blends with whatever is behind it). Color blending works between UIViews or CALayers. You can find blending modes here CICategoryCompositeOperation. To use a filter, just drop the CI
& lowercase the first letter of the name (e.g. CIDivideBlendMode
becomes divideBlendMode
). Here is some playground code to illustrate:
import UIKit
import PlaygroundSupport
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 900))
PlaygroundPage.current.liveView = view
let heightIncrement = view.frame.height / 13
let widthIncrement = view.frame.width / 7
// TOP EXAMPLE (UIViews)
let backgroundView = UIView(frame: CGRect(x: widthIncrement * 2,
y: heightIncrement,
width: widthIncrement * 3,
height: heightIncrement * 5))
backgroundView.backgroundColor = .black
view.addSubview(backgroundView)
let overlayView1 = UIView(frame: CGRect(x: widthIncrement,
y: heightIncrement * 2,
width: widthIncrement * 5,
height: heightIncrement))
overlayView1.backgroundColor = UIColor.yellow.withAlphaComponent(0.3)
overlayView1.layer.compositingFilter = "darkenBlendMode"
view.addSubview(overlayView1)
let overlayView2 = UIView(frame: CGRect(x: widthIncrement,
y: heightIncrement * 4,
width: widthIncrement * 5,
height: heightIncrement))
overlayView2.backgroundColor = UIColor.yellow.withAlphaComponent(0.3)
overlayView2.layer.compositingFilter = "divideBlendMode"
view.addSubview(overlayView2)
// BOTTOM EXAMPLE (CALayers)
let backgroundLayer = CALayer()
backgroundLayer.frame = CGRect(x: widthIncrement * 2,
y: heightIncrement * 7,
width: widthIncrement * 3,
height: heightIncrement * 5)
backgroundLayer.backgroundColor = UIColor.black.cgColor
view.layer.addSublayer(backgroundLayer)
let overlayLayer1 = CALayer()
overlayLayer1.frame = CGRect(x: widthIncrement,
y: heightIncrement * 8,
width: widthIncrement * 5,
height: heightIncrement)
overlayLayer1.backgroundColor = UIColor.yellow.withAlphaComponent(0.3).cgColor
overlayLayer1.compositingFilter = "darkenBlendMode"
view.layer.addSublayer(overlayLayer1)
let overlayLayer2 = CALayer()
overlayLayer2.frame = CGRect(x: widthIncrement,
y: heightIncrement * 10,
width: widthIncrement * 5,
height: heightIncrement)
overlayLayer2.backgroundColor = UIColor.yellow.withAlphaComponent(0.3).cgColor
overlayLayer2.compositingFilter = "divideBlendMode"
view.layer.addSublayer(overlayLayer2)
The result looks like this:
I confirmed that the same code works in iOS. Here's the view controller code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let heightIncrement = view.frame.height / 13
let widthIncrement = view.frame.width / 7
// TOP EXAMPLE (UIViews)
let backgroundView = UIView(frame: CGRect(x: widthIncrement * 2,
y: heightIncrement,
width: widthIncrement * 3,
height: heightIncrement * 5))
backgroundView.backgroundColor = .black
view.addSubview(backgroundView)
let overlayView1 = UIView(frame: CGRect(x: widthIncrement,
y: heightIncrement * 2,
width: widthIncrement * 5,
height: heightIncrement))
overlayView1.backgroundColor = UIColor.yellow.withAlphaComponent(0.3)
overlayView1.layer.compositingFilter = "darkenBlendMode"
view.addSubview(overlayView1)
let overlayView2 = UIView(frame: CGRect(x: widthIncrement,
y: heightIncrement * 4,
width: widthIncrement * 5,
height: heightIncrement))
overlayView2.backgroundColor = UIColor.yellow.withAlphaComponent(0.3)
overlayView2.layer.compositingFilter = "divideBlendMode"
view.addSubview(overlayView2)
// BOTTOM EXAMPLE (CALayers)
let backgroundLayer = CALayer()
backgroundLayer.frame = CGRect(x: widthIncrement * 2,
y: heightIncrement * 7,
width: widthIncrement * 3,
height: heightIncrement * 5)
backgroundLayer.backgroundColor = UIColor.black.cgColor
view.layer.addSublayer(backgroundLayer)
let overlayLayer1 = CALayer()
overlayLayer1.frame = CGRect(x: widthIncrement,
y: heightIncrement * 8,
width: widthIncrement * 5,
height: heightIncrement)
overlayLayer1.backgroundColor = UIColor.yellow.withAlphaComponent(0.3).cgColor
overlayLayer1.compositingFilter = "darkenBlendMode"
view.layer.addSublayer(overlayLayer1)
let overlayLayer2 = CALayer()
overlayLayer2.frame = CGRect(x: widthIncrement,
y: heightIncrement * 10,
width: widthIncrement * 5,
height: heightIncrement)
overlayLayer2.backgroundColor = UIColor.yellow.withAlphaComponent(0.3).cgColor
overlayLayer2.compositingFilter = "divideBlendMode"
view.layer.addSublayer(overlayLayer2)
}
}
And here's the result in the simulator: