ios 只需用矩形遮罩 UIView
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11391058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simply mask a UIView with a rectangle
提问by Accatyyc
I want to know how to simply mask the visible area of a UIView of any kind. All the answers/tutorials I've read so far describe masking with an image, gradient or creating round corners which is way more advanced than what I am after.
我想知道如何简单地屏蔽任何类型的 UIView 的可见区域。到目前为止,我读过的所有答案/教程都描述了使用图像、渐变或创建圆角进行遮罩,这比我所追求的要先进得多。
Example: I have a UIView with the bounds (0, 0, 100, 100) and I want to cut away the right half of the view using a mask. Therefore my mask frame would be (0, 0, 50, 100).
示例:我有一个边界为 (0, 0, 100, 100) 的 UIView,我想使用遮罩切掉视图的右半部分。因此,我的蒙版框将是 (0, 0, 50, 100)。
Any idea how to do this simply? I don't want to override the drawrect method since this should be applicable to any UIView.
知道如何简单地做到这一点吗?我不想覆盖 drawrect 方法,因为这应该适用于任何 UIView。
I've tried this but it just makes the whole view invisible.
我试过这个,但它只会使整个视图不可见。
CGRect mask = CGRectMake(0, 0, 50, 100);
UIView *maskView = [[UIView alloc] initWithFrame:mask];
viewToMask.layer.mask = maskView.layer;
回答by Accatyyc
Thanks to the link from MSK, this is the way I went with which works well:
感谢 MSK 的链接,这是我使用的方式,效果很好:
// Create a mask layer and the frame to determine what will be visible in the view.
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGRect maskRect = CGRectMake(0, 0, 50, 100);
// Create a path with the rectangle in it.
CGPathRef path = CGPathCreateWithRect(maskRect, NULL);
// Set the path to the mask layer.
maskLayer.path = path;
// Release the path since it's not covered by ARC.
CGPathRelease(path);
// Set the mask of the view.
viewToMask.layer.mask = maskLayer;
回答by Eugene Tartakovsky
Thanks for answers guys.
谢谢各位大佬解答。
In case someone can't find suitable answer on SO for this question for hours, like i just did, i've assembled a working gist in Swift 2.2 for masking
/clipping
UIView
with CGRect
/UIBezierPath
:
如果有人在这个问题上几个小时都找不到合适的答案,就像我刚刚做的那样,我已经在 Swift 2.2 中为masking
/clipping
UIView
和CGRect
/组装了一个工作要点UIBezierPath
:
https://gist.github.com/Flar49/7e977e81f1d2827f5fcd5c6c6a3c3d94
https://gist.github.com/Flar49/7e977e81f1d2827f5fcd5c6c6a3c3d94
extension UIView {
func mask(withRect rect: CGRect, inverse: Bool = false) {
let path = UIBezierPath(rect: rect)
let maskLayer = CAShapeLayer()
if inverse {
path.append(UIBezierPath(rect: self.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
func mask(withPath path: UIBezierPath, inverse: Bool = false) {
let path = path
let maskLayer = CAShapeLayer()
if inverse {
path.append(UIBezierPath(rect: self.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
}
Usage:
用法:
let viewSize = targetView.bounds.size
let rect = CGRect(x: 20, y: 20, width: viewSize.width - 20*2, height: viewSize.height - 20*2)
// Cuts rectangle inside view, leaving 20pt borders around
targetView.mask(withRect: rect, inverse: true)
// Cuts 20pt borders around the view, keeping part inside rect intact
targetView.mask(withRect: rect)
Hope it will save someone some time in the future :)
希望它会在将来为某人节省一些时间:)
回答by Geri Borbás
No need any mask at all. Just put it into a wrapper viewwith the smaller frame, and set clipsToBounds.
根本不需要任何口罩。只需将其放入具有较小框架的包装视图中,并设置clipsToBounds。
wrapper.clipsToBounds = YES;
回答by Dan Rosenstark
Very simple example in a Swift ViewController, based on the accepted answer:
很简单的例子在斯威夫特的ViewController,根据公认的答案:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let redView = UIView(frame: view.bounds)
view.addSubview(redView)
view.backgroundColor = UIColor.green
redView.backgroundColor = UIColor.red
mask(redView, maskRect: CGRect(x: 50, y: 50, width: 50, height: 50))
}
func mask(_ viewToMask: UIView, maskRect: CGRect) {
let maskLayer = CAShapeLayer()
let path = CGPath(rect: maskRect, transform: nil)
maskLayer.path = path
// Set the mask of the view.
viewToMask.layer.mask = maskLayer
}
}
Output
输出
回答by A-Live
An optional layer whose alpha channelis used as a mask to select between the layer's background and the result of compositing the layer's contents with its filtered background.
@property(retain) CALayer *mask
一个可选图层,其Alpha 通道用作蒙版,以在图层背景和图层内容与其过滤背景的合成结果之间进行选择。
@property(retain) CALayer *mask
The correct way to do what you want is to create the maskView
of the same frame (0, 0, 100, 100) as the viewToMask
which layer you want to mask. Then you need to set the clearColor for the path you want to make invisible (this will block the view interaction over the path so be careful with the view hierarchy).
做您想做的正确方法是创建与 您要遮罩的图层maskView
相同的帧(0、0、100、100)viewToMask
。然后,您需要为要使其不可见的路径设置 clearColor(这将阻止路径上的视图交互,因此请注意视图层次结构)。
回答by dengST30
Swift 5, thanks @Dan Rosenstark
Swift 5,感谢@Dan Rosenstark
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let red = UIView(frame: view.bounds)
view.addSubview(red)
view.backgroundColor = UIColor.cyan
red.backgroundColor = UIColor.red
red.mask(CGRect(x: 50, y: 50, width: 50, height: 50))
}
}
extension UIView{
func mask(_ rect: CGRect){
let mask = CAShapeLayer()
let path = CGPath(rect: rect, transform: nil)
mask.path = path
// Set the mask of the view.
layer.mask = mask
}
}
回答by jefimijana
Setting MaskToBounds
is not enough, for example, in scenario where you have UIImageView
that is positioned inside RelativeLayout
. In case that you put your UIImageView
to be near top edge of the layout and then you rotate your UIImageView
, it will go over layout and it won't be cropped. If you set that flag to true, it will be cropped yes, but it will also be cropped if UIImageView
is on the center of layout, and that is not what you want.
设置MaskToBounds
是不够的,例如,在场景中,你有UIImageView
那位于内侧RelativeLayout
。如果您将您的UIImageView
to 靠近布局的顶部边缘,然后旋转您的UIImageView
,它将越过布局并且不会被裁剪。如果您将该标志设置为 true,它将被裁剪为 yes,但如果UIImageView
位于布局的中心,它也会被裁剪,这不是您想要的。
So, determinating maskRect
is the right approach.
因此,确定maskRect
是正确的方法。