aheze
aheze

Reputation: 30278

How to crop view with mask, but leave cropped-out parts partially opaque instead of hidden?

I want to crop out a portion of a view. I followed this article: "How to mask one UIView using another UIView", and this is my code currently:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        /// show a green border around the image view's original frame
        let backgroundView = UIView(frame: CGRect(x: 50, y: 50, width: 200, height: 300))
        backgroundView.layer.borderColor = UIColor.green.cgColor
        backgroundView.layer.borderWidth = 4
        view.addSubview(backgroundView)
        
        let imageView = UIImageView(frame: CGRect(x: 50, y: 50, width: 200, height: 300))
        imageView.image = UIImage(named: "TestImage")
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        view.addSubview(imageView)
        
        // MARK: - Mask code
        let maskView = UIView(frame: CGRect(x: 80, y: 100, width: 100, height: 100))
        maskView.backgroundColor = .blue /// ensure opaque
        view.addSubview(maskView)
        
        imageView.mask = maskView
        
    }
}

The mask is working fine:

Without mask With mask
Full image with no cropping Only a small square of image visible, the rest is cropped out. A green border indicates the original, uncropped image's frame.

However, I want the parts of the image view that are cropped out to still be there, but just have a lower alpha. This is what it should look like:

Full image with cropping, but the parts that are cropped out are still there. They just have a lower alpha.

I've tried changing maskView.alpha to 0.25, but that just makes the part with the mask be less opaque.

Cropped image that has 0.25 alpha

How can I make the cropped-out parts still be there, but just a bit more transparent?

Preferably I don't want to make another view, because eventually I'll be using this on a camera preview layer — an extra view might have a cost on performance.


Edit: matt's answer

I tried adding a subview with a background color with less alpha:

let maskView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 300))
maskView.backgroundColor = UIColor.blue.withAlphaComponent(0.3)

let maskView2 = UIView(frame: CGRect(x: 80, y: 100, width: 100, height: 100))
maskView2.backgroundColor = UIColor.blue.withAlphaComponent(1)
maskView2.alpha = 0

maskView.addSubview(maskView2)

imageView.mask = maskView

But this is the result:

Entire image has 0.3 alpha

Upvotes: 2

Views: 668

Answers (1)

matt
matt

Reputation: 534958

It’s all in the transparency of the colors you paint the mask with. (The hues — what we usually think of as color — are irrelevant.) The masking depends upon the degree of transparency. Areas of the mask that are partially transparent will make the masked view be partially transparent.

So make the mask the whole size of the target view, and make the whole mask a partially transparent color, except for the central area which is an opaque color.

enter image description here

Upvotes: 2

Related Questions