I am using this code proposed by Bartosz to add a mask to an UIImageView. It works fine.
#import <QuartzCore/QuartzCore.h>
CALayer *mask = [CALayer layer];
mask.contents = (id)[[UIImage imageNamed:@"mask.png"] CGImage];
mask.frame = CGRectMake(0, 0, 320.0, 100.0);
yourImageView.layer.mask = mask;
yourImageView.layer.masksToBounds = YES;
In addition, I want to animate the mask, e.g. sliding the mask to the right, so that at the end of the animation, the mask is not applied to the UIImageView any more.
In my specific case, the mask uses a fully transparent image, so the UIImageView is not visible at the initial state (which works fine), but is expected to be so at the end of the animation. However, the idea may be reused to any other use case were masks need to be animated.
The idea is to manipulate the x-origin portion of the frame of the mask. So, I came up with this code:
[UIView animateWithDuration: 0.2
delay: 0
options: UIViewAnimationCurveEaseInOut
animations:^{
CGRect maskFrame = yourImageView.layer.mask.frame;
maskFrame.origin.x = 320.0;
yourImageView.layer.mask.frame = maskFrame;
}
completion:^(BOOL finished){}];
Unfortunately, the mask is applied to the whole UIImageView at any time, it’s not sliding to the right.
UPDATE 1:
This is the code I am actually using the set up the view and mask: It’s a UITableViewCell.
APPCell.m (APPCell.h “extends” UITableViewCell)
#import "APPCell.h"
#import <QuartzCore/QuartzCore.h>
@interface APPCell()
@property (strong, nonatomic) UIImageView *menu;
@property (strong, nonatomic) CALayer *menuMask;
...
@end
@implementation APPCell
...
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self.menu = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320.0, 88.0)];
[self.menu setBackgroundColor:[UIColor clearColor]];
[self.menu setImage:[UIImage imageNamed:@"cell_back"]];
[self addSubview:self.menu];
self.menuMask = [CALayer layer];
self.menuMask.contents = (id)[[UIImage imageNamed:@"cell_mask"] CGImage];
self.menuMask.frame = CGRectMake(0, 0, 320.0, 88.0);
self.menu.layer.mask = self.menuMask;
self.menu.layer.masksToBounds = YES;
}
...
Instead of animating with the help of UIKit, I am now using implicit animation of CoreAnimation to move the mask layer:
APPCell.m
...
- (void)swipeLeft
{
self.menuMask.position = CGPointMake(-320.0, 0.0);
}
...
I can confirm that swipeLeft is called. I expect the mask “to be gone” and to see the [UIImage imageNamed:@”cell_back”]], which I do when I uncomment self.menu.layer.mask = self.menuMask.
Solution:
Instead of setting the content on the CALayer, I set the background color to white. This is the code I am using:
self.menuSubMenuMask = [CALayer layer];
self.menuSubMenuMask.backgroundColor = [[UIColor whiteColor] CGColor];
self.menuSubMenuMask.frame = CGRectMake(320.0, 0.0, 320.0, 88.0);
self.tableCellSubMenu.layer.mask = self.menuSubMenuMask;
self.tableCellSubMenu.layer.masksToBounds = YES;
In order to show the UIImageView the CALayer is applied to, the CALayer must NOT be “above” the UIImageView.
Animation with UIKit of UIViews is much more limited than using Core Animation directly. In particular what you are trying to animate is not one of animatable properties of a UIView. In addition as clarified in the View Programming Guide for iOS:
This is the case in your example. You have added a CALayer to your view and UIKit will not be able to animate the result for you. On the other hand you can use Core Animation directly to animate the motion of your mask layer. You should be able to do this easily using implicit animation as described in the Core Animation Programming Guide. Please note that from the list of CALayer Animatable Properties that frame is not animatable. Instead you should use
position.