Background
I’m trying to create a mask using two UIView with the below code.
Masking works, but not in the way that I was intending, images below.
I’m trying to get masking to work like Image A, but I’m getting the masking in Image B.
Question
How do I create a mask like Image A with two UIView?
Code
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let redView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
redView.backgroundColor = .red
view.addSubview(redView)
let maskView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
maskView.backgroundColor = .blue
maskView.layer.cornerRadius = 100
redView.mask = maskView
}
}
2
Answers
Masking is something provided by the lower level Core Animation layers that back
UIViews
. You need to provide a LAYER to serve as a mask, not a view.That layer can either be a
CGImage
, in which case the alpha channel of the image is what determines the masking, or you can use a CAShapeLayer.For a circular shape like in your case a shape layer is likely the better choice.
Edit:
Check out the code in this answer:
https://stackoverflow.com/a/22019632/205185
Here’s the (very old Objective-C) code from that answer:
The Swift code would look something like this:
(I spent about a minute on that code. It likely contains a couple of syntax errors.)
Also note that if your app supports resizing, you’ll need to update your mask path if the owning view changes size (during device rotation, for example.)
The key observation is that a
mask
will reveal the underlying view/layer based upon the alpha channel of the mask. As the documentation says:Thus, a mask yields your scenario “B”.
You ask:
In short, this sort of inverted masking is not something you can just do with view’s and applying a corner radius of one of their layers. We would generally achieve that sort of inverse mask by masking the view’s
layer
with aCAShapeLayer
, where you can draw whatever shape you want.But, frankly, a
UIViewController
probably shouldn’t be reaching into aUIView
and adjusting its layer’s mask. I would define aCornersView
:By putting the rounding logic in
layoutSubviews
, that means that this rounding will be applied automatically regardless of the size. Then, you would use it like so:If you use storyboards, you might even make
CornersView
an@IBDesignable
and makecornerRadius
an@IBInspectable
.