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

Apply CAShapeLayer to main UIView except UIButton

下面是对整个 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

最简单的方法是让 UIButton 成为屏蔽视图的兄弟视图,而不是子视图。我意识到将按钮作为子视图可​​能是合乎逻辑的(特别是因为它看起来你的代码可能来自 UIViewController 子类),所以我会创建一个容器 UIView 来容纳所有的除了 mapCardsButton 之外的其他子视图并将掩码应用于此新视图。

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

  • self.view 有两个子视图:maskedContainerViewmapCardsButton
  • maskedContainerView 拥有 self.view 曾经拥有的所有子视图,除了 mapCardsButton
  • maskedContainerView.layer.mask = maskLayer.

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

• 掩码(视图)-> 按钮

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

• 视图 -> 遮罩(子视图)、按钮

这样你会得到相同的视觉效果,但使用底视图作为容器。在代码中:

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];

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

在 'atIndex'

时重要性为 view.layer.sublayers.count 而不是 0

请收下!

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

只需将按钮的 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];