How to get multiply blend mode on a plain UIView (

2020-05-31 06:18发布

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 image. Since adjusting the alpha isn't giving me the desired effect I'd like to use blend modes instead.

As far as I know you can only use blend modes on images and not plain views. The color of the view is dynamic so I can't just use a picture instead.

I also tried rasterizing the view to an image, but that got all pixely and odd or something, but maybe I did something wrong.

So, the basic question is: Is it possible to apply blend modes to views? Or should I take a completely different approach to reach the same goal?

2条回答
女痞
2楼-- · 2020-05-31 06:21

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()
查看更多
狗以群分
3楼-- · 2020-05-31 06: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:

description

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:

description

查看更多
登录 后发表回答