How can I change myLayer.contents with a set of images (i.e. switching between img1 and img2) during the translation? thanks!
UIImage *myImage = [UIImage imageNamed:#"img1.png"];
CALayer *myLayer = [CALayer layer];
myLayer.contents = (id)myImage.CGImage;
myLayer.Position = CGPointMake(0,0);
myLayer.Bounds=CGRectMake(0.0, 0.0, 50, 50);
[self.view.layer addSublayer:myLayer];
//translation1
CGPoint startPt = CGPointMake(10,10);
CGPoint endPt = CGPointMake(100,100);
CABasicAnimation *transl1 = [CABasicAnimation animationWithKeyPath:#"position"];
transl1.removedOnCompletion = FALSE;
transl1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transl1.fromValue = [NSValue valueWithCGPoint:startPt];
transl1.toValue = [NSValue valueWithCGPoint:endPt];
transl1.duration = 3;
transl1.fillMode = kCAFillModeForwards;
transl1.beginTime = 0;
[myLayer addAnimation: transl1 forKey: nil];
The walking man example:
I have dealt with exactly the same task, but I had to do a running spider which is 6 leg walk and has 12 frames.
It was actually very difficult to do and took me few months to perfect.
The thing is that the the waking man example is usually done by setting an array of image frames( First leg, Last Leg) to an animationImages property of UIImageView.
Then you turn the animation on and off together with moving character right and left and by this creating an illusion of walking.
Now the big problem arises when you want create an illusion of acceleration. There is no way to change the animation duration DURING the animation playback and this is a major setback that is very hard to overcome.
Here is the code that I produced to overcome this issue:
Here you define an array with the walking leg frames, frame per step.
animationImagesSpider = [NSArray arrayWithObjects:
[UIImage imageNamed:#"1#2x.png"], [UIImage imageNamed:#"2#2x.png"], [UIImage imageNamed:#"3#2x.png"], [UIImage imageNamed:#"4#2x.png"], [UIImage imageNamed:#"5#2x.png"], [UIImage imageNamed:#"6#2x.png"], [UIImage imageNamed:#"6#2x.png"], [UIImage imageNamed:#"8#2x.png"], [UIImage imageNamed:#"9#2x.png"], [UIImage imageNamed:#"10#2x.png"], [UIImage imageNamed:#"11#2x.png"], [UIImage imageNamed:#"1#2x.png"], nil];
Here you attach the array to the UIImageView:
imgViewSpider = [[UIImageView alloc] initWithFrame:CGRectMake(200,410,100,145)];
imgViewSpider.animationImages = animationImagesSpider;
Now if you simply call [imgViewSpider startAnimating]; this will start the animation at a constant speed until you stop it. To overcome this I have used a recursion that plays a short animation for each step and this allows to adjusts the duration between each steps:
- (void) spiderRun {
imgViewSpider.animationDuration= 0.51-(accSp/3.5);
[imgViewSpider setAnimationRepeatCount:222]; /// this is a dummy value that has no effect because animtion ends after the first frame
[imgViewSpider startAnimating];
[self performSelector:#selector(spiderRun) withObject:nil afterDelay: 0.5-(accSp/3.5)];
}
By constantly changing the accSp value, I can control the walk speed during the walk.
As the other poster said, create a second animation that animates the contents property of the layer to a new image.
I would suggest putting both animations into an animation group, and adding the animation group to the layer. Then you can easily control both the duration and start time of both animations. You could make the image swap take place over part of the total duration, timed to take place in the middle of the animation.
You'd set the start of the animation using the beginTime property, and the duration with the duration property.
You will need to create a second animation transl2, this animation will make the image swap. You will need to set the duration to a half of transl1 duration so that it will fall in the middle of the transl1 animation.
transl1.duration = 3
transl2.duration = 1.5
Related
I am trying to have an animation in which a mask is placed in the center of the view. Any image view that passes behind the mask appears. So here is my code so far, but the problem with this code is that it animates the mask with the image view.
UIView *maskView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.worldImageView.frame.size.height, self.worldImageView.frame.size.height)];
// ...position maskView...
maskView.layer.position = CGPointMake(CGRectGetMidX([self.view bounds]), CGRectGetMidY([self.view bounds]));
maskView.layer.backgroundColor = [UIColor blackColor].CGColor;
maskView.layer.cornerRadius = 90;
self.worldImage = [[UIImageView alloc] init];
self.worldImage.frame = self.worldImageView.frame;
self.worldImage.image = [UIImage imageNamed:#"continents.png"];
[maskView addSubview:self.worldImage];
[self.view addSubview:maskView];
CABasicAnimation* worldAnimation = [[CABasicAnimation alloc] init];
[worldAnimation setFromValue:[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width + 50, CGRectGetMidY([maskView bounds]))]];
[worldAnimation setToValue:[NSValue valueWithCGPoint:CGPointMake(-50, CGRectGetMidY([maskView bounds]))]];
worldAnimation.keyPath = #"position";
worldAnimation.duration = 6.0f;
worldAnimation.repeatCount = HUGE_VALF;
[[self.worldImage layer] addAnimation:worldAnimation forKey:nil];
I don't know if I explained this well enough. Please tell me if you need more info. Thank you in advance!
Your issue here is that the mask property of UIView is attached to that UIView - they can't move separately. Technically, it's actually attached to the view's underlying layer, but whatever.
If you want the image to appear as if it's passing in front of a circular window (so that you can see it as it goes by) you'll need to add it as a subview of the view with the mask. So, you might do something like this:
UIView *maskView = [[UIView alloc] init];
// ...position maskView...
maskView.layer.cornerRadius = 90;
maskView.clipsToBounds = YES;
self.worldImage = [[UIImageView alloc] init];
self.worldImage.frame = self.worldImageView.frame;
self.worldImage.image = [UIImage imageNamed:#"continents.png"];
[maskView addSubview:self.worldImage];
[self.view addSubview:maskView];
// ...animate worldImage back and forth...
Note that instead of using a CAShapeLayer, I simply put rounded corners on maskView; since you want a circular mask, it's a much simpler trick. Also, when animating worldImage, consider using one of UIView's block-based animation methods – they're a lot easier to handle for simple stuff like this.
i have this method i use to load many images to scroll view, but when the images load from the url my scroll view is stuck and i can't understand how to load them in the background so the user will not feel it.
this method will call few times (8) in "for" cycle.
- (void)loadPhotosToLeftscroll{
//getting image information from JSON
NSMutableDictionary *photoDict;
photoDict = [leftPhotoArray lastObject];
//getting the photo
NSString *photoPath = [photoDict objectForKey:#"photos_path"];
NSLog(#"photo Path:%#",photoPath);
NSData * imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:photoPath]];
UIImage *image = [UIImage imageWithData:imageData];
// use the image how you like, say, as your button background
//calculating the hight of next photo
UIImageView *leftImage = [leftBlockScroll.subviews lastObject];
//allocating photoView
UIImageView *photoView = [[UIImageView alloc]initWithFrame:CGRectMake(5 , leftImage.frame.origin.y + leftImage.frame.size.height+5, image.size.width/2, image.size.height/2 )];
photoView.userInteractionEnabled=YES;
[photoView.layer setMasksToBounds:YES];
[photoView.layer setCornerRadius:3];
//getting items list
NSDictionary *sh_items = [photoDict objectForKey:#"items"];
//adding image button
UIButton *imageOverButton = [UIButton buttonWithType:UIButtonTypeCustom];
imageOverButton.frame = CGRectMake(0, 0, photoView.frame.size.width, photoView.frame.size.height);
[imageOverButton addTarget:self action:#selector(LeftimagePressed:) forControlEvents:UIControlEventTouchUpInside];
[imageOverButton setTag:[leftPhotoArray count]-1];
[photoView addSubview:imageOverButton];
//adding sh button to imageView
[self addThe_sh_signs:sh_items To_ImageView:photoView];
//subViewing the image to the scrollView
[self insert_Image:image toImageView:photoView in_Scroll:leftBlockScroll];
//calclulating the position of next imageView in scroll.
nextLeftPhotoHight = photoView.frame.size.height + photoView.frame.origin.y + 5;
//calculating the hight of the highest scroll view in both.
leftBlockScroll.contentSize = CGSizeMake(160, [self theSizeOfScrollViewHight]);
rightBlocScroll.contentSize = CGSizeMake(160, [self theSizeOfScrollViewHight]);
isLoadindContant = NO;
[self.view reloadInputViews];
[leftBlockScroll reloadInputViews];
}
please do not send me to some link that trying to explain how to use the asynchronous.
Try to explain according the method you see here.
Im here for any question, that you need to ask to help me.
You will have to do it asynchronously in a proper way. I do not think there is any way around that. I subclassed an UIImageView object and placed many instances of it within the cells of a talbe (in your case within the scroll view). The subclass objects are initialized with an url and load their image asynchronously (with some caching so that the image is not loaded every time).
This tutorial helped me much in the beginning:
http://www.markj.net/iphone-asynchronous-table-image/
You will just have to adopt that to your scroll view. The underlaying principle remains the same.
I have a UIButton which has arrow kind of blue image set as
UIImage *arrowImage = [UIImage imageNamed:#"bluearrow.png"];
[self.prevbutton setBackgroundImage:arrowImage forState:UIControlStateNormal];
Now I have another image yellow.png, that I want to super impose on top of this button image and make a flashing animation continuously. How can I do this?
This should help you.
myButton.imageView.animationImages =
[NSArray arrayWithObjects:[UIImage imageNamed:#"image1.png"],
[UIImage imageNamed:#"image2.png"],
nil];
myButton.imageView.animationDuration = 0.5; //whatever you want (in seconds)
[myButton.imageView startAnimating];
As quoted from https://stackoverflow.com/a/7490535/716216
Is it possible to have the radiating circles like the user location annotation. So that custom annotations have radiating circles of other colors. If not is there a hack way to make it work?
Check this out. You may able to do what you need with that. With a combination of using Core Animation and subclassing MKCircleView or MKOverlayView.
http://yickhong-ios.blogspot.com/2012/04/animated-circle-on-mkmapview.html
It is possible to create a custom subclass of UIView that does this. A UIView with two sublayers, one for the center ball and one for the expanding rings. The ring layer and the ball layer can be created by subclassing CALayer and overriding drawInContext: so you can get any colors you want. Code to animate the rings so that they expand and fade out at the same time could use a CAAnimationGroup like this:
// expand the ring from the ball size to the ring's max size
CABasicAnimation *sizeAnim = [CABasicAnimation animationWithKeyPath:#"bounds"];
sizeAnim.fromValue = [NSValue valueWithCGRect:ballBounds];
sizeAnim.toValue = [NSValue valueWithCGRect:ringBoundsMax];
sizeAnim.duration = kRingExpansionTime;
// fade out the ring part way thru the animation
CABasicAnimation* alphaAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
alphaAnim.fromValue = [NSNumber numberWithFloat:1];
alphaAnim.toValue = [NSNumber numberWithFloat:0];
alphaAnim.beginTime = kRingExpansionTime * 0.7f; // start part way thru
alphaAnim.duration = kRingExpansionTime - alphaAnim.beginTime;
CAAnimationGroup* group = [CAAnimationGroup animation];
group.duration = kRingExpansionTime;
group.repeatCount = HUGE_VALF; // repeat forever
group.animations = [NSArray arrayWithObjects:sizeAnim, alphaAnim, nil];
[ringLayer addAnimation:group forKey:nil];
I'm trying to animate something where it's initially blurry then it comes into focus. I guess it works OK, but when the animation is done it's still a little blurry. Am I doing this wrong?
CABasicAnimation* blurAnimation = [CABasicAnimation animation];
CIFilter *blurFilter = [CIFilter filterWithName:#"CIGaussianBlur"];
[blurFilter setDefaults];
[blurFilter setValue:[NSNumber numberWithFloat:0.0] forKey:#"inputRadius"];
[blurFilter setName:#"blur"];
[[self layer] setFilters:[NSArray arrayWithObject:blurFilter]];
blurAnimation.keyPath = #"filters.blur.inputRadius";
blurAnimation.fromValue = [NSNumber numberWithFloat:10.0f];
blurAnimation.toValue = [NSNumber numberWithFloat:1.0];
blurAnimation.duration = 1.2;
[self.layer addAnimation:blurAnimation forKey:#"blurAnimation"];
Your problem is that the animation stops and is automatically removed, but the filter lingers with the tiniest of blur applied.
What you want to do is to remove the blur filter when the animation completes. You need to add a delegate to the CABasicAnimation instance and implement the -[id<CAAnimationDelegate> animationDidStop:finished:] method.
If you let self be the delegate in this case it should be fairly simple, add this line before adding the animation to your layer:
blurAnimation.delegate = self;
And the callback is equally simple:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
[[self layer] setFilters:nil];
}
If you're looking for an optimized way to animate a blur then I recommend creating a single blurred image of your view and then fading the blurred image from alpha 0 to 1 over the top of your original view. Seems nice and fast in tests.