I am working on a project in which A video is recorded.When recording is finished, I play video using AVPlayer adding layer to view. Now I want a gif image as adding layer to that view.
I successfully Add gif image as layer, but image is not animated. It is like a static image.I use Library for GIF image.
My code is below
self.avPlayer = [AVPlayer playerWithURL:self.urlstring];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
AVPlayerLayer *videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
videoLayer.frame = self.preview_view.bounds;
videoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.preview_view.layer addSublayer:videoLayer];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"02" withExtension:#"gif"];
CALayer *layer = [[CALayer alloc]init];
layer.frame = self.img_gif.bounds;
layer.contents = (id) [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]].CGImage;
[self.preview_view.layer addSublayer:layer];
Please help me with it
Thank you
I have successfully done it. I added my GIF image to layer.
- (CAKeyframeAnimation *)createGIFAnimation:(NSData *)data{
CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)(data), nil);
int frameCount =(int) CGImageSourceGetCount(src);
// Total loop time
float time = 0;
// Arrays
NSMutableArray *framesArray = [NSMutableArray array];
NSMutableArray *tempTimesArray = [NSMutableArray array];
// Loop
for (int i = 0; i < frameCount; i++){
// Frame default duration
float frameDuration = 0.1f;
// Frame duration
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(src,i,nil);
NSDictionary *frameProperties = (__bridge NSDictionary*)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString*)kCGImagePropertyGIFDictionary];
// Use kCGImagePropertyGIFUnclampedDelayTime or kCGImagePropertyGIFDelayTime
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString*)kCGImagePropertyGIFUnclampedDelayTime];
if(delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
} else {
NSNumber *delayTimeProp = gifProperties[(NSString*)kCGImagePropertyGIFDelayTime];
if(delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Make sure its not too small
if (frameDuration < 0.011f){
frameDuration = 0.100f;
}
[tempTimesArray addObject:[NSNumber numberWithFloat:frameDuration]];
// Release
CFRelease(cfFrameProperties);
// Add frame to array of frames
CGImageRef frame = CGImageSourceCreateImageAtIndex(src, i, nil);
[framesArray addObject:(__bridge id)(frame)];
// Compile total loop time
time = time + frameDuration;
}
NSMutableArray *timesArray = [NSMutableArray array];
float base = 0;
for (NSNumber* duration in tempTimesArray){
//duration = [NSNumber numberWithFloat:(duration.floatValue/time) + base];
base = base + (duration.floatValue/time);
[timesArray addObject:[NSNumber numberWithFloat:base]];
}
// Create animation
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:#"contents"];
animation.duration = time;
animation.repeatCount = HUGE_VALF;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.values = framesArray;
animation.keyTimes = timesArray;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.calculationMode = kCAAnimationDiscrete;
return animation;
}
To add image in layer of view write below code
CALayer *layer = [CALayer layer];
layer.frame = self.preview_view.bounds;
CAKeyframeAnimation *animation = [self createGIFAnimation:[NSData dataWithContentsOfURL:url]];
[layer addAnimation:animation forKey:#"contents"];
["YOUR VIEW".layer addSublayer:layer];
Try this with your image view.
CALayer *layer = [CALayer layer];
layer.backgroundColor = [[UIColor whiteColor] CGColor];
layer.contents = (id) [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]].CGImage;
NSURL *url = [[NSBundle mainBundle] URLForResource:#"02" withExtension:#"gif"];
[[self.view layer] addSublayer:layer];
[layer setNeedsDisplay];
[self.view addSubview: animateImageView];
Related
I'm trying to convert following (link) swift code in objective c.
https://stackoverflow.com/a/49100870/797196
CTFontRef helveticaBold = CTFontCreateWithName( CFSTR("Helvetica-Bold"), 60.0, NULL);
NSString* unicodeString =#"Window Title";
CGColorRef color = [UIColor blueColor].CGColor;
NSNumber* underline = [NSNumber numberWithInt:
kCTUnderlineStyleSingle|kCTUnderlinePatternDot];
NSDictionary* attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id)helveticaBold, (NSString*)kCTFontAttributeName,
color, (NSString*)kCTForegroundColorAttributeName,
underline, (NSString*)kCTUnderlineStyleAttributeName, nil];
NSAttributedString* stringToDraw = [[NSAttributedString alloc]
initWithString:unicodeString
attributes:attributesDict];
CGMutablePathRef letters = CGPathCreateMutable();
// CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)#"Avenir",20,nil);
CTLineRef lines = CTLineCreateWithAttributedString((CFAttributedStringRef)stringToDraw);
CFArrayRef runArray = CTLineGetGlyphRuns(lines);
CAShapeLayer *pathLayer = [CAShapeLayer layer];
for (int i = 0; i < CFArrayGetCount(runArray); i++) {
CTRunRef run = CFArrayGetValueAtIndex(runArray, i);
CFDictionaryRef dictRef = CTRunGetAttributes(run);
NSDictionary *dict = (__bridge NSDictionary*)dictRef;
CTFontRef runFont = (__bridge CTFontRef)(dict[(NSString*)kCTFontAttributeName]);
for (int runGlyphIndex=0; runGlyphIndex<CTRunGetGlyphCount(run); runGlyphIndex++) {
CGGlyph glyph;
CGPoint position = CGPointZero;
CTRunGetGlyphs(run, CFRangeMake(runGlyphIndex, 1), &glyph);
CTRunGetPositions(run, CFRangeMake(runGlyphIndex, 1), &position);
CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, nil);
CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y);
CGPathAddPath(letters, &t, letter);
CAShapeLayer *pathL = [CAShapeLayer layer];
// pathLayer.frame = _pathLayerView.bounds;
CGRect rect = CGPathGetBoundingBox(letter);
rect.origin = position;
pathL.frame = rect;
pathL.geometryFlipped = true;
pathL.path = letter;
pathL.strokeColor = UIColor.blueColor.CGColor;
pathL.fillColor = UIColor.redColor.CGColor;
pathL.lineWidth = 4.0;
pathL.lineJoin = kCALineJoinBevel;
CABasicAnimation *stroke = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
stroke.fromValue = #(0.0);
stroke.duration = 3.0f;
stroke.repeatCount = 0;
[pathL addAnimation:stroke forKey:nil];
[pathLayer addSublayer:pathL];
}
}
[_pathLayerView.layer addSublayer:pathLayer];
But the problem is letters alignment is not in required position. "i","n","o" letters y position starts from the top. & its obvious, because I didn't use the position of the letters.
I find out the positions of the letters using CTRunGetPositions, but I dont know how to use it or where to use it.
I am creating a video based application where I have to select any video from local gallery and have to add a text using CATextLayer over the Video. For this I am using below code:
- (void) createWatermark:(UIImage*)image video:(NSURL*)videoURL
{
if (videoURL == nil)
return;
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:videoURL options:nil];
AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack* compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack* clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
ofTrack:clipVideoTrack
atTime:kCMTimeZero error:nil];
[compositionVideoTrack setPreferredTransform:[[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];
// create the layer with the watermark image
CALayer* aLayer = [CALayer layer];
aLayer.contents = (id)image.CGImage;
aLayer.frame = CGRectMake(50, 100, image.size.width, image.size.height);
aLayer.opacity = 0.9;
//sorts the layer in proper order
AVAssetTrack* videoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CGSize videoSize = [videoTrack naturalSize];
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:aLayer];
// create text Layer
CATextLayer* titleLayer = [CATextLayer layer];
titleLayer.backgroundColor = [UIColor clearColor].CGColor;
titleLayer.string = #"Dummy text";
titleLayer.font = CFBridgingRetain(#"Helvetica");
titleLayer.fontSize = 28;
titleLayer.shadowOpacity = 0.5;
titleLayer.alignmentMode = kCAAlignmentCenter;
titleLayer.frame = CGRectMake(0, 50, videoSize.width, videoSize.height / 6);
[parentLayer addSublayer:titleLayer];
//create the composition and add the instructions to insert the layer:
AVMutableVideoComposition* videoComp = [AVMutableVideoComposition videoComposition];
videoComp.renderSize = videoSize;
videoComp.frameDuration = CMTimeMake(1, 30);
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
/// instruction
AVMutableVideoCompositionInstruction* instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]);
AVAssetTrack* mixVideoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mixVideoTrack];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject: instruction];
// export video
_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
_assetExport.videoComposition = videoComp;
NSLog (#"created exporter. supportedFileTypes: %#", _assetExport.supportedFileTypes);
NSString* videoName = #"NewWatermarkedVideo.mov";
NSString* exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL* exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
//Final code here
switch (_assetExport.status)
{
case AVAssetExportSessionStatusUnknown:
NSLog(#"Unknown");
break;
case AVAssetExportSessionStatusWaiting:
NSLog(#"Waiting");
break;
case AVAssetExportSessionStatusExporting:
NSLog(#"Exporting");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(#"Created new water mark image");
_playButton.hidden = NO;
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Failed- %#", _assetExport.error);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Cancelled");
break;
}
}
];
}
Using above code, I can able to set a text over my video. But now I have to give either FadeIN/Fade Out animation on CATextLayer OR to display moving text on Video. Please advise me. Thanks in Advance!
Try to use CAKeyframeAnimation class declared in core animation framework.
for example:
//start from zero opacity
titleLayer.opacity = 0;
CAKeyframeAnimation *fadeInAndOut = [CAKeyframeAnimation animationWithKeyPath:#"opacity"];
fadeInAndOut.duration = 5.0; //5 seconds will be your fade in fade out animation.
fadeInAndOut.autoreverses = NO;
// from 0.0 * animDuration time to 0.2 * animDuration time your animation will animate opacity from zero to 1.0.
// from 0.2 * animDuration time to 0.8 * animDuration time your opacity will be 1.0
// from 0.8 * animDuration time to 1.0 * animDuration time your animation will animate opacity from 1.0 opacity to zero.
fadeInAndOut.keyTimes = #[#(0.0), #(0.2), #(0.8), #(1.0)];
fadeInAndOut.values = #[#(0.0), #(1.0), #(1.0), #(0.0)];
fadeInAndOut.beginTime = 1.0;
fadeInAndOut.removedOnCompletion = NO;
fadeInAndOut.fillMode = kCAFillModeBoth;
[titleLayer addAnimation:fadeInAndOut forKey:nil];
I hope it's clear for you. using same way you can animate your label position.
UPDATE
for animate position try this
CAKeyframeAnimation *fadeInAndOut = [CAKeyframeAnimation animationWithKeyPath:#"position"];
fadeInAndOut.duration = 5.0;
fadeInAndOut.autoreverses = NO;
fadeInAndOut.keyTimes = #[#(0.0), #(0.2), #(0.8), #(1.0)];
fadeInAndOut.values = #[[NSValue valueWithCGPoint:CGPointMake(20, 40)],
[NSValue valueWithCGPoint:CGPointMake(200, 40)],
[NSValue valueWithCGPoint:CGPointMake(200, 40)],
[NSValue valueWithCGPoint:CGPointMake(400, 40)]];
fadeInAndOut.beginTime = 1.0;
fadeInAndOut.removedOnCompletion = NO;
fadeInAndOut.fillMode = kCAFillModeBoth;
[titleLayer addAnimation:fadeInAndOut forKey:nil];
I hardcoded points for explain purpose. you can calculate points and animation duration yourself.
First add parent layer:
let parentLayer = CALayer()
After that add overlayer for adding fade animation:
let overlayLayer = CALayer()
And call extension for adding fade animation:
overlayLayer.addFadeAnimationWithTime(showTime: startTime, endTime: endTime)
And add this to parent layer:
parentLayer.addSublayer(overlayLayer)
Extension for fade animation with startTime and endTime:
extension CALayer {
func addFadeAnimationWithTime(showTime:CGFloat, endTime:CGFloat) {
let fadeInAnimation = CABasicAnimation.init(keyPath: "opacity")
fadeInAnimation.duration = 1
fadeInAnimation.fromValue = NSNumber(value: 0)
fadeInAnimation.toValue = NSNumber(value: 1)
fadeInAnimation.isRemovedOnCompletion = false
fadeInAnimation.beginTime = CFTimeInterval(showTime)
fadeInAnimation.fillMode = CAMediaTimingFillMode.backwards
self.add(fadeInAnimation, forKey: "fadeIn")
if endTime > 0 {
let fadeOutAnimation = CABasicAnimation.init(keyPath: "opacity")
fadeOutAnimation.duration = 1
fadeOutAnimation.fromValue = NSNumber(value: 1)
fadeOutAnimation.toValue = NSNumber(value: 0)
fadeOutAnimation.isRemovedOnCompletion = false
fadeOutAnimation.beginTime = CFTimeInterval(endTime)
fadeOutAnimation.fillMode = CAMediaTimingFillMode.forwards
self.add(fadeOutAnimation, forKey: "fadeOut")
}
}
}
I am using this and this for reference. I am new for using UIBezierPath, and i want to draw path on character(letter) code i am using is as follow.
CGMutablePathRef letters = CGPathCreateMutable();
CTFontRef font = CTFontCreateWithName(CFSTR("Courier New"), 200.0f, NULL);
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:CFBridgingRelease(font), kCTFontAttributeName,nil];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:#"B"
attributes:attrs];
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString);
CFArrayRef runArray = CTLineGetGlyphRuns(line);
// for each RUN
for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++)
{
// Get FONT for this run
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
// for each GLYPH in run
for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++)
{
// get Glyph & Glyph-data
CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1);
CGGlyph glyph;
CGPoint position;
CTRunGetGlyphs(run, thisGlyphRange, &glyph);
CTRunGetPositions(run, thisGlyphRange, &position);
// Get PATH of outline
{
CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y);
CGPathAddPath(letters, &t, letter);
CGPathRelease(letter);
}
}
}
CFRelease(line);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointZero];
[path appendPath:[UIBezierPath bezierPathWithCGPath:letters]];
CGPathRelease(letters);
CFRelease(font);
NSLog(#"==> %#",path);
// Creates layer
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = drawingView.bounds;
pathLayer.bounds = CGPathGetBoundingBox(path.CGPath);
//pathLayer.backgroundColor = [[UIColor yellowColor] CGColor];
pathLayer.geometryFlipped = NO;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [[UIColor blackColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = 3.0f;
pathLayer.lineJoin = kCALineJoinBevel;
[drawingView.layer addSublayer:pathLayer];
self.pathLayer = pathLayer;
// Add pointer
UIImage *penImage = [UIImage imageNamed:#"hand.png"];
CALayer *penLayer = [CALayer layer];
penLayer.contents = (id)penImage.CGImage;
penLayer.anchorPoint = CGPointMake(0.35f, 0.98f);
penLayer.frame = CGRectMake(0.0f, 0.0f, penImage.size.width, penImage.size.height);
[pathLayer addSublayer:penLayer];
self.penLayer = penLayer;
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 5.0;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
[self.pathLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
CAKeyframeAnimation *penAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
penAnimation.duration = 5.0;
penAnimation.path = self.pathLayer.path;
penAnimation.calculationMode = kCAAnimationPaced;
penAnimation.delegate = self;
[self.penLayer addAnimation:penAnimation forKey:#"position"];
This code draws latter latter in double line like the image below
instead i want to draw latter in single line like the image below
and the hand should draw the lines on centre of the font and not the border.
I have an animation which is a bar, which travels across the screen according to a timer which shortens each time something is tapped. My problem is that the animation only plays once. I try calling the animation to reset and begin the bar again, but nothing happens. Here is some code:
-(IBAction)targetTapped:(id)sender {
[Time invalidate];
targX = arc4random() %619;
targY = arc4random() %925;
NSLog([NSString stringWithFormat:#"X = %li", (long)targX]);
NSLog([NSString stringWithFormat:#"Y = %li", (long)targY]);
Target.center = CGPointMake(targX, targY);
Score = Score + 1;
if (Score >= 225) {
timeMax = 0.5;
}
else {
timeMax = 5 - (Score * 0.02);
}
Time = [NSTimer scheduledTimerWithTimeInterval:timeMax target:self selector:#selector(Lose) userInfo:nil repeats:NO];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.0,895.0)];
[path addLineToPoint:CGPointMake(768.0, 895.0)];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = self.view.bounds;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [[UIColor blueColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = 5.0f;
pathLayer.lineJoin = kCALineJoinBevel;
[self.view.layer addSublayer:pathLayer];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = timeMax;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
[pathLayer animationForKey:#"strokeEnd"];
[pathLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
}
You can create the pathLayer once:
[self.pathLayer removeAnimationForKey:#"strokeEnd"];
if (self.pathLayer == nil) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.0,895.0)];
[path addLineToPoint:CGPointMake(768.0, 895.0)];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = self.view.bounds;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [[UIColor blueColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = 5.0f;
pathLayer.lineJoin = kCALineJoinBevel;
[self.view.layer addSublayer:pathLayer];
self.pathLayer = pathLayer;
}
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = timeMax;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
[self.pathLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
I have a method which translates a view and optionally scales it while translating. I am using animation groups and adding the required animations as needed. Here are the animation cases working perfectly.
Translation (x or y axis or both) (OK)
Scaling (OK)
Translation while scaling (MOSTLY)
However, doing a translation while scaling works only when the starting scalefactor is 1. When the view is already scaled, I notice most of the transition jumping instead of animating, although the end result of scaling and translation is correct.
I am posting part of the code for clarification. The problem occurs only when previousZoomScale is not 1! I appreciate any directions you can point me to.
-(void)performAnimationForView: (AnimationType)animationType
WithDX: (CGFloat)dx
AndDY: (CGFloat)dy
Scale: (CGFloat)scale
Duration: (CGFloat)duration
{
CABasicAnimation *translateXAnimation = nil, *translateYAnimation = nil, *scaleAnimation = nil;
NSString* animationGroupName;
CGPoint newDxDy;
switch (animationType)
{
case kAnimationTranslateAndScale:
// set animation key
animationGroupName = #"translatescale";
translateXAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
translateXAnimation.repeatCount = 0;
translateXAnimation.autoreverses = NO;
translateXAnimation.removedOnCompletion = NO;
translateXAnimation.fillMode = kCAFillModeForwards;
translateXAnimation.fromValue = [NSNumber numberWithFloat: self.previousDxDy.x]; // previous point we're tranlsating from
translateXAnimation.toValue = [NSNumber numberWithFloat:dx]; // destination point
translateYAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.y"];
translateYAnimation.repeatCount = 0;
translateYAnimation.autoreverses = NO;
translateYAnimation.removedOnCompletion = NO;
translateYAnimation.fillMode = kCAFillModeForwards;
translateYAnimation.fromValue = [NSNumber numberWithFloat: self.previousDxDy.y];
translateYAnimation.toValue = [NSNumber numberWithFloat:dy];
newDxDy = CGPointMake(dx, dy);
self.previousDxDy = newDxDy;
// scaling animation
scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.autoreverses = NO;
scaleAnimation.repeatCount = 0;
scaleAnimation.removedOnCompletion = NO;
scaleAnimation.fillMode = kCAFillModeForwards;
scaleAnimation.fromValue = [NSNumber numberWithDouble: self.previousZoomScale]; // initial zoom scale
scaleAnimation.toValue = [NSNumber numberWithDouble:scale]; // target scale
self.previousZoomScale = scale;
break;
}
NSMutableArray* animationArray = [[NSMutableArray alloc] initWithObjects: nil];
if (translateXAnimation != nil)
[animationArray addObject: translateXAnimation];
if (translateYAnimation != nil)
[animationArray addObject: translateYAnimation];
if (scaleAnimation != nil)
[animationArray addObject: scaleAnimation];
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.duration = duration;
theGroup.removedOnCompletion = NO;
theGroup.fillMode = kCAFillModeForwards;
theGroup.repeatCount = 0;
theGroup.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear];
theGroup.animations = animationArray;
theGroup.delegate = self;
[theGroup setValue: animationGroupName forKey: #"animationtype"];
[self.backgroundImageView.layer addAnimation: theGroup forKey: animationGroupName];
}