只需用矩形遮罩 UIView
Posted
技术标签:
【中文标题】只需用矩形遮罩 UIView【英文标题】:Simply mask a UIView with a rectangle 【发布时间】:2012-07-08 14:46:44 【问题描述】:我想知道如何简单地掩盖任何类型的 UIView 的可见区域。到目前为止,我阅读的所有答案/教程都描述了使用图像、渐变或创建圆角进行遮罩,这比我所追求的要先进得多。
示例:我有一个边界为 (0, 0, 100, 100) 的 UIView,我想使用遮罩切除视图的右半部分。因此,我的蒙版框架将是 (0, 0, 50, 100)。
知道如何简单地做到这一点吗?我不想重写 drawrect 方法,因为这应该适用于任何 UIView。
我已经尝试过了,但它只会使整个视图不可见。
CGRect mask = CGRectMake(0, 0, 50, 100);
UIView *maskView = [[UIView alloc] initWithFrame:mask];
viewToMask.layer.mask = maskView.layer;
【问题讨论】:
我不确定我是否理解,但你为什么不把你的视图框架改成蒙版呢?例如 viewToMask.frame = 掩码; (或者如果你想展示的话,反之亦然。) 这是行不通的,因为视图可能有应该被切断的可拉伸图像,或者即使被屏蔽也应该仍然可用的控件。更改框架会更改图像拉伸或使控件无法使用。 检查这是否有帮助 ***.com/questions/7241966/… 它有帮助:) 添加我作为答案的方式。 或者这个,逐个查看屏蔽***.com/questions/6805444/masking-a-uiview 【参考方案1】:一个可选层,其 alpha 通道 用作掩码以进行选择 图层背景与合成结果之间 图层的内容及其过滤背景。
@property(retain) CALayer *mask
正确的方法是创建与viewToMask
相同帧(0、0、100、100)的maskView
要屏蔽哪个图层。然后,您需要为要使其不可见的路径设置 clearColor(这将阻止路径上的视图交互,因此请注意视图层次结构)。
【讨论】:
感谢您的回答!我想我找到了一种不使用 alpha 的更简单的方法,所以我添加了自己的答案。 @Accatyyc 不错的解决方案,我通过将maskLayer
和maskRect
重命名为homeTeamMaskLayer
和homeTeamMaskRect
对其进行了编辑,以便它编译:) 需要等待它被批准虽然并且感谢更新。
啊,感谢您的编辑建议。我以相反的方式更新了它,所以它对我以外的其他项目有意义:)【参考方案2】:
感谢 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;
【讨论】:
感谢您花时间写下您自己的答案!它使学习过程变得更加简单。现在我们也是声望好友了! :) 非常有用,我不知道你可以用路径制作图层,这正是我想要的。谢谢! 非常感谢。达维拉说的。同样在这里-非常感谢您编写此示例。工作出色。 (我用它在集合视图上创建了一个动画蒙版,这样我就可以拉起集合视图并让它在另一个视图之上展开,这样它就可以接管全屏——最终结果非常漂亮:-) ) 非常感谢!我被过滤器问题困扰了好几天,我试图屏蔽 UIImage,但屏蔽 UIView 是一个更好的解决方案!我希望你能通过堆栈溢出发送啤酒! 我整天都在找这个。爱你。【参考方案3】:根本不需要任何面具。 只需将其放入具有较小框架的包装视图,然后设置clipsToBounds。
wrapper.clipsToBounds = true
【讨论】:
如果你想剪切一个控件,它实际上不起作用,因为它不会响应其父框架之外的触摸。此外,这基本上与设置蒙版的作用相同,只是现在您需要考虑一个相对框架。 我认为它的性能更高,因为这可能只在引擎盖下调整纹理坐标,但应用蒙版可能会进行 alpha 混合。 您始终可以覆盖 -pointInside: 以获取框架外的响应。不过,这可能真的是一笔开销。 更简单的方法!谢谢。【参考方案4】:设置MaskToBounds
是不够的,例如,在UIImageView
位于RelativeLayout
内部的情况下。如果您将UIImageView
放在布局的顶部边缘附近,然后旋转您的UIImageView
,它将超过布局并且不会被裁剪。如果您将该标志设置为 true,它将被裁剪是,但如果 UIImageView
位于布局的中心,它也会被裁剪,这不是您想要的。
因此,确定maskRect
是正确的方法。
【讨论】:
【参考方案5】:Swift 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
输出
【讨论】:
【参考方案6】:谢谢大家的回答。
如果有人在这个问题上找不到合适的答案,就像我刚刚做的那样,我已经在 Swift 2.2 中为masking
/clipping
UIView
和CGRect
组装了一个工作要点/UIBezierPath
:
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
用法:
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)
希望它会在未来为某人节省一些时间:)
【讨论】:
经过几个小时的搜索,我找到了你,我的救星。非常感谢! :)【参考方案7】: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
【讨论】:
以上是关于只需用矩形遮罩 UIView的主要内容,如果未能解决你的问题,请参考以下文章