How to get multiply blend mode on a plain UIView (not UIImage)

后端 未结 2 1095
刺人心
刺人心 2021-02-04 01:47

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

相关标签:
2条回答
  • 2021-02-04 02:25

    Take a look at the docs for CALayer's compositingFilter: https://developer.apple.com/documentation/quartzcore/calayer/1410748-compositingfilter

    On your color overlay view you can set view.layer.compositingFilter to a CICategoryCompositeOperation to achieve blending with the content behind it. Here is some sample playground code with a multiply blend mode applied to test it out (replace the UIImage(named: "") with your own image for testing)

    import UIKit
    import PlaygroundSupport
    
    class MyViewController : UIViewController {
        override func loadView() {
    
            let mainView = UIView()
            self.view = mainView
    
            let image = UIImageView()
            image.translatesAutoresizingMaskIntoConstraints = false;
            image.image = UIImage(named: "maxresdefault.jpg")
            mainView.addSubview(image)
    
            let overlay = UIView()
            overlay.translatesAutoresizingMaskIntoConstraints = false;
            overlay.backgroundColor = .red
            overlay.layer.compositingFilter = "multiplyBlendMode"
            mainView.addSubview(overlay)
    
            mainView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": view]))
            mainView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": view]))
    
            mainView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": overlay]))
            mainView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": overlay]))
        }
    }
    
    PlaygroundPage.current.liveView = MyViewController()
    
    0 讨论(0)
  • 2021-02-04 02:37

    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:

    0 讨论(0)
提交回复
热议问题