将 CAShapeLayer 应用于除 UIButton 之外的主 UIView

Posted

技术标签:

【中文标题】将 CAShapeLayer 应用于除 UIButton 之外的主 UIView【英文标题】:Apply CAShapeLayer to main UIView except UIButton 【发布时间】:2016-04-04 13:30:39 【问题描述】:

这是一个将掩码应用于整个 UIView 的代码:

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
[maskPath appendPath:[UIBezierPath bezierPathWithArcCenter:self.mapCardsButton.center
                                                    radius:self.mapCardsButton.frame.size.height/2.0f
                                                startAngle:0.0f
                                                  endAngle:2.0f*M_PI
                                                 clockwise:NO]];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.fillRule  = kCAFillRuleEvenOdd;
maskLayer.fillColor = [UIColor blackColor].CGColor;
maskLayer.path = maskPath.CGPath;
self.view.layer.mask = maskLayer;

问题是我想将上面的掩码应用于整个 UIView,除了一个特定的 UIButton(mapCardsButton) 也在同一个 UIView 上。 有可能吗?

UPD:我试过了

[self.view.layer insertSublayer:maskLayer atIndex:0];

而不是

self.view.layer.mask = maskLayer;

但我的 self.view 丢失了 alpha 通道,并且 maskLayer 的动画不再起作用

这是一个项目代码:https://www.dropbox.com/s/b94qcwxzoi23kwk/test_04092016.zip?dl=0

【问题讨论】:

[self.view.layer insertSublayer:gradient atIndex:0]; 添加此代码后,我的 UIView 变为黑色,没有 alpha,并且 maskLayer 的动画不再起作用。 所以你想屏蔽全视图,只显示当前显示的完整按钮框架 专家级 你在说什么?请看这张图片imgur.com/6w6mLqm 另一张图片imgur.com/xrgokDV 【参考方案1】:

您为什么不尝试以下方法?而不是下面的堆栈:

• 掩码(视图)-> 按钮

在附加的子视图中使视图背景颜色清晰,并执行以下操作:

• 视图 -> 掩码(子视图)、按钮

这样您将获得相同的视觉效果,但使用底部视图作为容器。在代码中:

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
[maskPath appendPath:[UIBezierPath bezierPathWithArcCenter:self.mapCardsButton.center
                                                    radius:self.mapCardsButton.frame.size.height/2.0f
                                                startAngle:0.0f
                                                  endAngle:2.0f*M_PI
                                                 clockwise:NO]];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.fillRule  = kCAFillRuleEvenOdd;
maskLayer.fillColor = [UIColor blackColor].CGColor;
maskLayer.path = maskPath.CGPath;

UIView *maskedView = [[UIView alloc] initWithFrame:self.view.bounds];    
maskedView.mask = maskLayer;

self.view.backgroundColor = [UIColor clearColor];
[self.view addSubView:maskedView];
[self.view addSubView:self.mapCardsButton];

【讨论】:

【参考方案2】:

最简单的方法是让UIButton 成为屏蔽视图的兄弟视图,而不是子视图。我意识到将按钮作为子视图可​​能是合乎逻辑的(特别是因为看起来您的代码可能来自UIViewController 子类),所以我将创建一个容器UIView 来保存所有其他子视图mapCardsButton 并将遮罩应用到这个新视图。

假设你调用了新视图maskedContainerView,那么:

self.view 有两个子视图:maskedContainerViewmapCardsButton maskedContainerView 包含 self.view 以前的所有子视图,除了 mapCardsButton maskedContainerView.layer.mask = maskLayer

【讨论】:

感谢您的回复。我尝试了您的解决方案,但仍然无法正常工作。现在它显示 mapCardsButton 但不会产生“洞”。这是一个带有代码的项目:dropbox.com/s/b94qcwxzoi23kwk/test_04092016.zip?dl=0 嘿。抱歉耽搁了。我刚刚看了你的代码。我认为缺少的只是maskedContainerView 应该包含self.view 曾经使用的内容,即maskedContainerView 应该将其背景颜色设置为self.view 当前设置的灰色/蓝色背景颜色。那么self.view应该是完全透明的; self.view.backgroundColor = [UIColor clearColor]. stefandouganhyde,不错的解决方法!我在想那个案子 太棒了!所以它的外观和功能都符合您的预期,@Sergio?【参考方案3】:

[maskedContainerView.layer insertSublayer:maskLayer atIndex:(unsigned)maskedContainerView.layer.sublayers.count];

重要性是 view.layer.sublayers.count 在 'atIndex' 处不是 0

请收下!

【讨论】:

【参考方案4】:

基于您的代码。我不确定这是你想要的。

只需将按钮的 UIBezierPath 添加到您的 maskPath。 像这样的代码(基于您的代码)

const NSInteger kHoleSize = 100;

UIButton *mapCardsButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kHoleSize, kHoleSize )];
[mapCardsButton setTitle:@"BUTTON" forState:UIControlStateNormal];
mapCardsButton.backgroundColor = [UIColor redColor];

[self.view addSubview:mapCardsButton];



UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds];


UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:self.view.center
                                                          radius:kHoleSize/2.0f
                                                      startAngle:0.0f
                                                        endAngle:2.0f*M_PI
                                                       clockwise:NO];

UIBezierPath *buttonPath = [UIBezierPath bezierPathWithRect:mapCardsButton.frame];
[circlePath appendPath:buttonPath];


[maskPath appendPath:circlePath];
[maskPath setUsesEvenOddFillRule:YES];

CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = maskPath.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.fillColor = [UIColor blackColor].CGColor;
maskLayer.opacity = 0.9;

[self.view.layer addSublayer:maskLayer];

【讨论】:

以上是关于将 CAShapeLayer 应用于除 UIButton 之外的主 UIView的主要内容,如果未能解决你的问题,请参考以下文章

CSS:将 CSS 样式应用于除 Material Angular 之外的所有内容

使用媒体查询将 CSS 应用于除 IE 之外的所有浏览器

如何将 CSS3 过渡应用于除背景位置之外的所有属性?

将border-right应用于除最后一个元素之外的所有元素

关于 CORS,为啥我部署的 Azure 应用程序适用于除一个用户之外的所有人?

转换一个描边的 CAShapeLayer