Aplicar CAShapeLayer a UIView principal, excepto UIButton

Aquí hay un código que aplica la máscara a toda la 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; 

El problema es que quiero aplicar la máscara anterior a toda la UIView excepto un UIB específico (mapCardsButton) que también está en la misma UIView. Es posible de hacer?

UPD: lo intenté

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

en lugar de

 self.view.layer.mask = maskLayer; 

pero mi vista personal perdió el canal alfa y la animation de maskLayer ya no funciona

Aquí hay un proyecto con código: https://www.dropbox.com/s/b94qcwxzoi23kwk/test_04092016.zip?dl=0

¿Por qué no intentas lo siguiente? en lugar de la siguiente stack:

• máscara (vista) -> button

haga que el color de background de la vista sea claro, en una subvista adicional y haga lo siguiente:

• vista -> máscara (subView), button

De esta manera, tendrá el mismo efecto visual, pero use la vista inferior como contenedor. En codigo:

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

La forma más sencilla sería que el UIButton sea ​​una vista de hermanos de la vista enmascarada, en lugar de una subvista. Me doy count de que podría tener sentido lógico que el button sea una subvista (especialmente dado que parece que tu código probablemente UIViewController una subclass UIViewController ), por lo que crearía una UIView contenedor que mantenga todas las otras subvistas aparte de mapCardsButton y aplicará la máscara a esta nueva vista.

Entonces diga que llamó a la nueva vista maskedContainerView y luego:

  • self.view tiene dos subvenciones: maskedContainerView y mapCardsButton
  • maskedContainerView contiene todas las subvenciones que usa self.view , excepto mapCardsButton
  • maskedContainerView.layer.mask = maskLayer .

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

La importancia es view.layer.sublayers.count no 0 en 'atIndex'

éxito ¡Por favor, tómalo!

Base en su código. No estoy seguro de esto es lo que quieres. introduzca la descripción de la imagen aquí

solo agregue el UIBezierPath del button a su máscaraPath. el código como este (Base en su código)

 const NSInteger kHoleSize = 100; UIButton *mapCardsButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kHoleSize, kHoleSize )]; [mapCardsButton setTitle:@"BUTTON" forState:UIControlStateNormal]; mapCardsButton.backgroundColor = [UIColor networkingColor]; [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];