I have a UIImageView with an array of images it iterates through to form an animation.
[imageView setAnimationImages:arrayOfImages];
I now need to move this image view along a path whilst it is animating. I had a look through the source code of this example. It uses UIBezierPath to create the path and CALayer to represent the object that moves along the path. But how would I do this for a animating UIImageView?
Many thanks for any advice.
[EDIT] Please note I also had to add the UIImageView as a subview to the current view.
Finally figured it out using the example I gave before. Here are my steps:
Create the path. (note P = CGPointMake in the code below)
UIBezierPath *trackPath = [UIBezierPath bezierPath];
[trackPath moveToPoint:P(160, 25)];
[trackPath addCurveToPoint:P(300, 120)
controlPoint1:P(320, 0)
controlPoint2:P(300, 80)];
[trackPath addCurveToPoint:P(80, 380)
controlPoint1:P(300, 200)
controlPoint2:P(200, 480)];
....
Create the UIImageView and give it an array of animation images.
UIImageView *test = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[test setAnimationImages:[NSArray arrayWithObjects:[UIImage imageNamed:#"bee-1"],
[UIImage imageNamed:#"bee-2"], nil]];
[test startAnimating];
Set the UIImageView's layer position and add the layer to the view's layer:
[test.layer setPosition:P(160,25)];
[self.view.layer addSublayer:test.layer];
Create the CAKeyframeAnimation:
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
anim.path = trackPath.CGPath;
anim.rotationMode = kCAAnimationRotateAuto;
anim.repeatCount = HUGE_VALF;
anim.duration = 8.0;
[test.layer addAnimation:anim forKey:#"race"];
Related
Please help me. I am phasing a problem, show a delete button on top of the view.
Without using bezier path showing like this
When i use bezier path is showing like this
how i can show the button.
This is the code i am using
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
[view1 setBackgroundColor:[UIColor orangeColor]];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view1.bounds byRoundingCorners:UIRectCornerTopLeft| UIRectCornerTopRight cornerRadii:CGSizeMake(10.0, 10.0)];
// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = view1.bounds;
maskLayer.path = maskPath.CGPath;
// Set the newly created shape layer as the mask for the image view's layer
view1.layer.mask = maskLayer;
[self.view addSubview:view1];
UIButton *bt1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[bt1 setTitle:#"D" forState:UIControlStateNormal];
[bt1 setFrame:CGRectMake(87, -10, 25, 25)];
[view1 addSubview:bt1];
please help me. Thanks in advance.
You could always add the button in your superview depending of the view's position.
What #Larme said is true ,when you're making a view you're masking all the subviews that view has.
In case you don't want to do that just enter in your view's drawRect and draw there transparent corners to achieve the same effect.
well I know that every imageViews have a layer (we can access it with :imageView.layer).I would like to use the layer of my imageView and add a subLayer to it's layer:shapeLayer(that is a CAShapeLayer) My code doesn't work, it doesn't show the shape layer!
- (void)viewDidLoad
{
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[self.view addSubview:imageView];
}
- (void)anotherMethod
{
[imageView.layer addSublayer:shapeLayer];
}
How can I solve this please ?
Try this:
[outputImage.layer insertSublayer:shapeLayer atIndex:0];
I solved similar problem by using UIView below UIImageView and setting a layer to UIView. When you add a layer to UIImageView at index 0, your image will not be visible.
I have a UIView called photoView. It has a subview of class UIImageView, that has same bounds and has a clear background color. And I add a gradientLayer to photoView.
- (void)viewDidLoad
{
[super viewDidLoad];
// Adding gradient background to UIImageView
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = self.photoImageView.bounds;
gradientLayer.colors = #[(id)[UIColor customUltraLightGrayColor].CGColor, (id)[UIColor customUltraLightGrayColor].CGColor, (id)[UIColor customDarkGrayColor].CGColor];
gradientLayer.locations = #[#(0.0), #(0.6)];
[self.photoView.layer insertSublayer:gradientLayer atIndex:0];
}
As a result I get this:
This could have several reasons, for example:
Did you #import <QuartzCore/QuartzCore.h> (and / or CoreGraphics/CoreGraphics.h> depending on what you are doing in the rest of your code)?
You could have set a wrong CGRectMake when initializing the CALayer which is not inside your visible frame (Like CGRectMake(5000,5000,...,...)) or one of the size properties is 0?
Try setting the frame for layer:
Follow the three steps
CALayer layerToBeAdded = [[CALayer alloc] init];
[layerToBeAdded setFrame:imgView.frame];
[imgView.layer addSublayer:layerToBeAdded];
Instead of allocating CALayer, you can use [imgView layer]
And to add image to layer do it like this
layerToBeAdded.contents = (id)imgXYZ.CGImage;
Assuming that you are talking about just one UIImageView (imageView == outputImage ???)
//in another method:
{
[imageView.layer addSublayer:shapeLayer]; //Where is outputImage initialized?
}
Here is a solution:
CALayer *pulseLayer_ = [[CALayer layer] retain];
pulseLayer_.backgroundColor = [[UIColor whiteColor] CGColor];
pulseLayer_.bounds = CGRectMake(0., 0., 80., 80.);
pulseLayer_.cornerRadius = 12.;
pulseLayer_.position = self.view.center;
[self.view.layer addSublayer:pulseLayer_];
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = pulseLayer_.bounds;
imageLayer.cornerRadius = 10.0;
imageLayer.contents = (id) [UIImage imageNamed:#"jacklogo.png"].CGImage;
imageLayer.masksToBounds = YES;
[pulseLayer_ addSublayer:imageLayer];
[pulseLayer_ setNeedsDisplay];
I'm trying to slide down an image in an UIImageView, but I don't know which combination of UIContentMode and animation property is the right one to make that happen.
The image should always have the same size and should not be streched... all I want is, that nothing is visible first and then the frame extends and reveals the image.
Maybe it's easier if you see what I mean:
So, it sounds rather easy, but what UIContentMode should I use for the UIImageView and what property should I animate? Thank you!
I took your lead and made a screencast as well. Was this what you had in mind?
I put the animation repeating indefinitely so it would be easier to capture with a video, but it can be started at the press of a button, as well as frozen in place, showing the popover and its contents, until reversed to be hidden again.
I used Core Animation for that, instead of animating a UIView, since I wanted to use the mask property of CALayer to hide the popover and reveal it with a sliding animation.
Here is the code I used (same as in the video):
- (void)viewDidLoad
{
// Declaring the popover layer
CALayer *popover = [CALayer layer];
CGFloat popoverHeight = 64.0f;
CGFloat popoverWidth = 200.0f;
popover.frame = CGRectMake(50.0f, 100.0f, popoverWidth, popoverHeight);
popover.contents = (id) [UIImage imageNamed:#"popover.png"].CGImage;
// Declaring the mask layer
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(0, - popoverHeight, popoverWidth, popoverHeight);
maskLayer.backgroundColor = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f].CGColor;
// Setting the animation (animates the mask layer)
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"position.y"];
animation.byValue = [NSNumber numberWithFloat:popoverHeight];
animation.repeatCount = HUGE_VALF;
animation.duration = 2.0f;
[maskLayer addAnimation:animation forKey:#"position.y"];
//Assigning the animated maskLayer to the mask property of your popover
popover.mask = maskLayer;
[self.view.layer addSublayer:popover];
[super viewDidLoad];
}
NOTE: You have to import the QuartzCore framework into your project and write this line in your header file: #import <QuartzCore/QuartzCore.h>.
Tells if this works for you or if you need any more help setting this up.
Try this code.
Consider the UIImageView as imageView.
imageView.contentMode = UIViewContentModeScaleAspectFill;
CGRect imageRect = imageView.frame;
CGRect origImgRect = imageRect;
imageRect.size.height = 5;
imageView.frame = imageRect;
[UIView animateWithDuration:2.0
animations:^{imageView.rect = origImgRect;}
completion:^(BOOL finished){ }];
In one of my view I am adding shadow to a view. Thing is that the shadow shows white spaces on left & right edges. I want to remove these spaces.
Here is my code:
UIView *myView = [[ISTView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 35)];
myView.backgroundColor = [UIColor greyColor];
[myView.layer setShadowOffset:CGSizeMake(0.0, 5.0)];
[myView.layer setShadowOpacity:0.8];
[myView.layer setShadowRadius:2.0];
[myView.layer setShadowColor:[UIColor blackColor].CGColor];
[self.view addSubview:myView];
[myView release];
Here is my view's o/p:
If you want homogenous shadow without side effects you can draw it in graphics editor, save to png and place UIImageView with stretchable image on your view. And don't forget to set clipToBounds to NO.
UIView *myView = [[ISTView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 35)];
myView.backgroundColor = [UIColor greyColor];
myView.clipToBounds = NO;
UIImageView *shadowView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 35, 320, 10)];
shadowView.image = [UIImage imageWithName:#"my-shadow.png"];
[myView addSubview:shadowView];
[shadowView release];
[self.view addSubview:myView];
[myView release];
It would be cheaper for system to draw cached existing image above view hierarcy than calculate layer's shadow.
Use shadowPath to make the shadow larger then the view
view.layer.shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, view.frame.size.width+30, view.frame.size.height)].CGPath;
One solution I could think of and is working also is to adjust the view's frame by 2 pixels in X position and width:
UIView *myView = [[ISTView alloc] initWithFrame:CGRectMake(-2.0, 0.0, 324.0, 35)];
But this is not a cleaner approach of doing this. If anyone has better solution, please guide.
Try this, remove the code:
[myView.layer setShadowRadius:2.0];
According to the Mac Dev Center docs, you should be able to set the contents property of a CALayer and have that render automatically. However, I still can't get a simple image to show up by adding a sublayer to the UIView's root later. I've tried multiple different variations; here's what I have so far:
(Note: I know there are other ways of rendering images; for my purposes I'd like to use CALayer's for some of the more complicated stuff I'm going to get into).
(in viewDidDisplay() of the ViewController):
CALayer *theLayer = [CALayer layer];
[[[self view] layer] addSublayer:theLayer];
theLayer.contents = (id)[[UIImage imageNamed:#"mypic.png"] CGImage];
theLayer.contentsRect = CGRectMake(0.0f, 0.0f, 300.0f, 300.0f);
theLayer.bounds = CGRectMake(0.0f, 0.0f, 300.0f, 400.0f);
Anyone know what I'm doing wrong?
Thanks!
You could load the image into a UIImageView, which is decended from UIView and therefore has it's own layer property.
UIImageView *imgView = [[UIImageView alloc] initWithFrame:frame];
imgView.image = [UIImage imageNamed:#"mypic.png"];
[[[self view] layer] addSublayer:[imgView layer]];
[imgView release];
You don't need to set the contentsRect (and if you do, it should be in the unit coordinate space, probably just CGRectMake(0, 0, 1.0, 1.0).
You might want to set the layer's position property.
You need to create two CALayer . This is perfect way to display the image within the CALayer.
CALayer *pulseLayer_ = [[CALayer layer] retain];
pulseLayer_.backgroundColor = [[UIColor whiteColor] CGColor];
pulseLayer_.bounds = CGRectMake(0., 0., 80., 80.);
pulseLayer_.cornerRadius = 12.;
pulseLayer_.position = self.view.center;
[self.view.layer addSublayer:pulseLayer_];
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = pulseLayer_.bounds;
imageLayer.cornerRadius = 10.0;
imageLayer.contents = (id) [UIImage imageNamed:#"jacklogo.png"].CGImage;
imageLayer.masksToBounds = YES;
[pulseLayer_ addSublayer:imageLayer];
[pulseLayer_ setNeedsDisplay];
I think its make solution to your problem.