0

I've done simple CALayer masks before but I think I'm getting confused on what they do. I'm trying to have a punch out effect with several (2) views.

Here's what I have so far. I'm looking to have a white square with punched out label and image (so you can see the brown background through it. Where am I going wrong?

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor brownColor];

    self.viewToPunch = [[UIView alloc] initWithFrame:CGRectZero];
    [self.view addSubview:self.viewToPunch];
    self.viewToPunch.backgroundColor = [UIColor whiteColor];

    self.punchLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    self.punchLabel.textColor = [UIColor blackColor];
    self.punchLabel.font = [UIFont boldSystemFontOfSize:20.0];
    self.punchLabel.text = @"punch";
    self.punchLabel.textAlignment = NSTextAlignmentCenter;

    self.punchImage = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"plus"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
    [self.punchImage setContentMode:UIViewContentModeCenter];

    self.viewsToPunch = @[self.punchLabel,self.punchImage];

    [self punch:self.viewToPunch withUIViews:self.viewsToPunch];
}

- (void)punch:(UIView *) viewToPunch withUIViews:(NSArray *)viewsToPunch
{
    CALayer *punchMask = [CALayer layer];
    punchMask.frame = viewToPunch.frame;

    NSMutableArray *sublayers = [[NSMutableArray alloc] init];
    for (UIView *views in viewsToPunch){
        [sublayers addObject:views.layer];
    }
    punchMask.sublayers = sublayers;
    punchMask.masksToBounds = YES;

    viewToPunch.layer.mask = punchMask;
}

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    self.viewToPunch.frame = CGRectMake(50, 50, 100, 100);
    self.punchLabel.frame = CGRectMake(0, 0, 100, 100);
    self.punchImage.frame = CGRectMake(0, 0, self.viewToPunch.frame.size.width, 40.);

    [self punch:self.viewToPunch withUIViews:self.viewsToPunch];
}

so far

So not only do the frames seem to be off, it seems to be the opposite of a punch out. How do I invert the mask and fix up the frames?

Thanks a lot for any help! I put it in a method punch:withUIViews: so I can hopefully reuse it in other areas.

Mike S
  • 4,092
  • 5
  • 35
  • 68
  • Can you write down in the question what you think the mask does and how it works. Also, why are you setting the frames to a zero rect? – Wain Aug 07 '14 at 10:47
  • Thats how I code - all frames are cgrectzero and I do the resizing in the viewWillLAyoutSubviews or layoutSubviews (so animation, frame changes, etc are handled automatically. The way I thought a CALayer mask works is, pixel by pixel it checks the alpha channel on the mask and adjusts the alpha on the other view by the alpha value on the mask.. – Mike S Aug 07 '14 at 10:53

2 Answers2

0

When you apply a mask to a CALayer, it only gets drawn in the parts where the mask is not transparent. But you're simply applying an empty (transparent) mask, with the wrong coordinates (which is why your view isn't completely transparent: the mask isn't covering the view completely; it should be punchMask.frame = viewToPunch.bounds;)

You might want to look into CAShapeLayer and assign it a path. Use that as mask layer.

For example, see CAShapeLayer mask view or Getting Creative with CALayer Masks (cached blog post).

Community
  • 1
  • 1
DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • Oh ok, It seems as if it isn't impossible then. How do I invert a mask so its a punch-out effect rather than what I have there? – Mike S Aug 07 '14 at 10:59
  • Hmmm, after re-reading what you want to achieve (solid view with text cut-out), I think it'll be hard to do this with pure CoreAnimation since you can't reverse the alpha of a layer and you also cannot use a transparent text color with a `CATextLayer` to create the necessary mask dynamically… It might be easier to do this by drawing it yourself and using [kCGBlendModeDestinationOut](http://stackoverflow.com/a/17817917/400056). See also [Drawing a path with subtracted text using CoreGraphics](http://stackoverflow.com/questions/18716751/drawing-a-path-with-subtracted-text-using-core-graphics). – DarkDust Aug 07 '14 at 11:13
0

I tried to combine mask of CAGradationLayer and CAShapeLayer, and It is possible.

https://stackoverflow.com/a/32220792/3276863

Community
  • 1
  • 1
taku_oka
  • 453
  • 6
  • 18