问题
I have 2 images. One is in the back of the other. I want to fade-out the top image starting from the left corner. How can I do this?
Should I use gradient mask?
回答1:
Here's a technique that will fade out whatever's in a CALayer, from top-left to bottom-right, revealing whatever is underneath the CALayer.
Let's say we're going to fade out the layer of a UIImageView
called self.fadeView
.
We'll create a CAGradientLayer and use it as self.fadeView.layer.mask
. The gradient will go from alpha=0 (transparent) to alpha=1 (opaque) using four stops: 0, 0, 1, 1. Yes, two zeros and then two ones. When we want fadeView
to be opaque, we'll set the stop locations to -1, -.5, 0, 1. That way the two alpha=0 stops are completely outside of the layer bounds. When we want fadeView
to be transparent, we'll set the stop locations to 0, 1, 1.5, 2. That way the two alpha=1 stops are completely outside of the layer bounds. The CAGradientLayer
will automatically animate changes to its stop locations, creating a cross-fade effect.
Here's the code:
#import "ViewController.h"
@implementation ViewController
@synthesize fadeView = _fadeView;
static NSArray *locations(float a, float b, float c, float d)
{
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:a],
[NSNumber numberWithFloat:b],
[NSNumber numberWithFloat:c],
[NSNumber numberWithFloat:d],
nil];
}
// In my test project, I put a swipe gesture recognizer on fadeView in my XIB
// with direction = Up and connected it to this action.
- (IBAction)fadeIn
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithDouble:2.0] forKey:kCATransactionAnimationDuration];
((CAGradientLayer *)self.fadeView.layer.mask).locations = locations(-1, -.5, 0, 1);
[CATransaction commit];
}
// In my test project, I put a swipe gesture recognizer on fadeView in my XIB
// with direction = Down and connected it to this action.
- (IBAction)fadeOut
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithDouble:2.0] forKey:kCATransactionAnimationDuration];
((CAGradientLayer *)self.fadeView.layer.mask).locations = locations(0, 1, 1.5, 2);
[CATransaction commit];
}
- (void)viewDidLoad
{
[super viewDidLoad];
CAGradientLayer *mask = [CAGradientLayer layer];
mask.frame = self.fadeView.bounds;
mask.colors = [NSArray arrayWithObjects:
(__bridge id)[UIColor clearColor].CGColor,
(__bridge id)[UIColor clearColor].CGColor,
(__bridge id)[UIColor whiteColor].CGColor,
(__bridge id)[UIColor whiteColor].CGColor,
nil];
mask.startPoint = CGPointZero; // top left corner
mask.endPoint = CGPointMake(1, 1); // bottom right corner
self.fadeView.layer.mask = mask;
[self fadeIn]; // initialize mask.locations
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end
回答2:
Define your own CALayer
subclass with its own actionForKey
animation for the key contents
.
@interface CustomLayer: CALayer
@end
@implementation CustomLayer
+ (id<CAAction>)actionForKey:(NSString*)event {
if ([event isEqualToString:@"contents"]) {
CATransition* basicAnimation = [CATransition animation];
basicAnimation.type = kCATransitionMoveIn;
basicAnimation.subtype = kCATransitionFromLeft;
return basicAnimation;
} else {
return nil;
}
}
@end
Doing like this, whenever you set the contents
property of your CustomLayer
object, the transition will be shown:
CustomLayer* layer = [CustomLayer layer];
layer.contents = <FIRST_CGIMAGEREF_HERE>;
...
layer.contents = <SECOND_CGIMAGEREF_HERE>;
As usual, you can wrap the property assignment in a transaction:
[CATransaction begin];
....
[CATransaction end];
if you want more control on the duration of the transition, but in any case the transition will be applied.
EDIT:
For the kind of transition you would like to have, you can have a look at this sample on GitHub. Look for the ShutterTransition. It is not exactly what you are looking for, but it could lead you along the right path.
来源:https://stackoverflow.com/questions/8346837/how-to-apply-partial-fade-in-out-in-ios