Adding outline shadow to a UIView which is iOS 3.0 compatible - iphone

I have two UIViewControllers A and B and they are added as subviews in the AppDelegate with B on top of A.
When a UIButton on B is tapped B slides off to the left with the following code:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(slideOutFinished)];
simonSaysView.view.frame = CGRectMake(40-BView.view.frame.size.width, BView.view.frame.origin.y, BView.view.frame.size.width, BView.view.frame.size.height);
[UIView commitAnimations];
On the right edge I want a 20px drop shadow but i cannot use the shadow properties of BView.view.layer.shadow.... because its 3.2/4.0+ only. And the performance of the animation is awful, the slide is lagging extremely much (Its fluent without the shadow).
I'm thinking using a custom UIView and do some magic in drawRect but is this possible or can i only draw within the bounds of the view?
Hope some of you guys and girls can help me.
Cheers
objneodude

Solved with the following code
// Add drop shadow to the view.
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(self.view.frame.size.width, 0, 30, self.view.frame.size.height);
gradientLayer.colors = [NSArray arrayWithObjects:
(id)[UIColor blackColor].CGColor,
(id)[UIColor clearColor].CGColor,
nil];
gradientLayer.startPoint = CGPointMake(-2, 0.5);
gradientLayer.endPoint = CGPointMake(1, 0.5);
[self.view.layer addSublayer:gradientLayer];

I had the same problem, after trying various ideas, I just added a subview a shadow colour (Gray) behind the UIView I needed to have a shadow, see code: (Included is the code for >3.2.x/4.x as well.
/*Shaded/rounded borders on subviews*/
self.viewOne.layer.cornerRadius = 10;
self.viewOne.layer.borderColor = [UIColor darkGrayColor].CGColor;
self.viewOne.layer.borderWidth = 0.8;
self.viewTwo.layer.cornerRadius = 10;
self.viewTwo.layer.borderColor = [UIColor darkGrayColor].CGColor;
self.viewTwo.layer.borderWidth = 0.8;
self.viewThree.layer.cornerRadius = 10;
self.viewThree.layer.borderColor = [UIColor darkGrayColor].CGColor;
self.viewThree.layer.borderWidth = 0.8;
if (SYSTEM_VERSION_LESS_THAN(#"3.2")) {
self.shadowOne.layer.cornerRadius = 10;
self.shadowTwo.layer.cornerRadius = 10;
self.shadowThree.layer.cornerRadius = 10;
}
else{
//Use QuartzCore to make shadows etc.
self.viewOne.layer.shadowColor = [[UIColor grayColor] CGColor];
self.viewOne.layer.shadowOffset = CGSizeMake(2, 2);
self.viewOne.layer.shadowOpacity = 0.6;
self.viewOne.layer.shouldRasterize = YES;
self.viewOne.layer.shadowRadius = 2;
self.viewTwo.layer.shadowColor = [[UIColor grayColor] CGColor];
self.viewTwo.layer.shadowOffset = CGSizeMake(2, 2);
self.viewTwo.layer.shadowOpacity = 0.6;
self.viewTwo.layer.shouldRasterize = YES;
self.viewTwo.layer.shadowRadius = 2;
self.viewThree.layer.shadowColor = [[UIColor grayColor] CGColor];
self.viewThree.layer.shadowOffset = CGSizeMake(2, 2);
self.viewThree.layer.shadowOpacity = 0.6;
self.viewThree.layer.shouldRasterize = YES;
self.viewThree.layer.shadowRadius = 2;
}

Related

Image rotate and scale

I need to rotate and scale a UIImageView image with the help of UISlider.
There are three condition when UISlider value is in its middle position then the original image will be its original position.
Second case, When slider value is maximum then image will rotate with 45 degree add bit scale.
Third case, when slider value is in its minimum position then image will rotate 45 degree in opposite direction and also bit scale.
I used this code but did not get desired result.
-(IBAction)sliderMoved:(id)sender
{
UIImage *image = [UIImage imageNamed:#"landscape.jpg"];
photoImage.transform = CGAffineTransformMakeRotation(slider.value * 2*M_PI_2 / slider.maximumValue);
CGFloat scale=0.5;
NSLog(#"sliderVlaue=%f",slider.value);
if ((slider.value) >(0.75)) {
scale =(.25+ slider.value);
} else {
scale =(0.75 +slider.value);
}
CGAffineTransform currentTransform = photoImage.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[photoImage setTransform:newTransform];
}
you can try this code
CGFloat Angle=(((int)slider.value*M_PI)/180);
transform=CGAffineTransformScale(transform, photoImage.scale, photoImage.scale);
transform= CGAffineTransformRotate(transform,Angle);
photoImage.transform = transform;
You can use this code for image rotation
imageview.transform = CGAffineTransformMakeRotation(M_PI);
For scaling an image
-(IBAction)grow
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:YES];
CGRect b = grower.bounds;
b.size.height = 200;
b.size.width = 200;
grower.bounds = b;
[UIView commitAnimations];
}
I tried my self with the help of given hints and able to way out from my problem. here is the code`
in you h file declare UIImageView *photoImage;
UIView *canvas;
CAShapeLayer *_marque;
And in view did load
if (!_marque) {
_marque = [CAShapeLayer layer] ;
_marque.fillColor = [[UIColor clearColor] CGColor];
_marque.strokeColor = [[UIColor grayColor] CGColor];
_marque.lineWidth = 1.0f;
_marque.lineJoin = kCALineJoinRound;
_marque.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10],[NSNumber numberWithInt:5], nil];
_marque.bounds = CGRectMake(photoImage.frame.origin.x, photoImage.frame.origin.y, 0, 0);
_marque.position = CGPointMake(photoImage.frame.origin.x + canvas.frame.origin.x, photoImage.frame.origin.y + canvas.frame.origin.y);
}
[[self.view layer] addSublayer:_marque];
- (IBAction) sliderMoved:(id)sender
{
CGFloat scale=0;
NSLog(#"sliderVlaue=%f",slider.value);
if ((slider.value) >(0.77)) {
scale =(.5+ slider.value);
photoImage.transform = CGAffineTransformMakeRotation(((4*slider.value)*(M_PI/180)));
CGAffineTransform currentTransform = photoImage.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale-.25, scale-.25);
[photoImage setTransform:newTransform];
NSLog(#"max=%f",scale);
}else if(slider.value< 0.77 && slider.value >.73){
photoImage.transform=CGAffineTransformIdentity;
photoImage.frame=imageframe;
scale =(0.5 +slider.value);
NSLog(#"mid=%f",scale);
}
else{
scale =(.77 +(1.0-slider.value));
photoImage.transform = CGAffineTransformMakeRotation((((-4)*(slider.value))*(M_PI/180)));
CGAffineTransform currentTransform = photoImage.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[photoImage setTransform:newTransform];
NSLog(#"min=%f",scale);
}
//_lastScale = 1;
[self showOverlayWithFrame:photoImage.frame];
}
-(void)showOverlayWithFrame:(CGRect)frame {
if (![_marque actionForKey:#"linePhase"]) {
CABasicAnimation *dashAnimation;
dashAnimation = [CABasicAnimation animationWithKeyPath:#"lineDashPhase"];
[dashAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];
[dashAnimation setToValue:[NSNumber numberWithFloat:15.0f]];
[dashAnimation setDuration:0.5f];
[dashAnimation setRepeatCount:HUGE_VALF];
[_marque addAnimation:dashAnimation forKey:#"linePhase"];
}
_marque.bounds = CGRectMake(frame.origin.x, frame.origin.y, 0, 0);
_marque.position = CGPointMake(frame.origin.x + canvas.frame.origin.x, frame.origin.y + canvas.frame.origin.y);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, frame);
[_marque setPath:path];
CGPathRelease(path);
_marque.hidden = NO;
}
You can do it with the following code:
- (void)viewDidLoad
{
[super viewDidLoad];
imgToRotate = [[UIImageView alloc]initWithFrame:CGRectMake(48, 208, 240, 240)];
imgToRotate.image = [UIImage imageNamed:#"rtm.jpeg"];
[self.view addSubview:imgToRotate];
}
- (IBAction)slideToRotateScale:(UISlider *)sender
{
sender.maximumValue = 1.0;
sender.minimumValue = -1.0;
imgToRotate.transform = CGAffineTransformRotate(CGAffineTransformMakeScale(fabsf(sender.value), fabs(sender.value)), sender.value*M_PI/4);
}

animating the CAEmitterCell Color property

I have a CAEmitterCell and I have set it up with a specific colour. The documentation says that this property is animatable, and I would like to animate this between a number of different colours for the different players in my game (all of whom choose their color at the start).
Here is my EmitterCell when I set it up:
//
// Emitter Cells
//
// 'New Emitter' cell configuration
newEmitter = [CAEmitterCell emitterCell];
newEmitter.scaleSpeed = 10;
newEmitter.lifetime = 2.481715;
newEmitter.velocity = 332.3636968085106;
newEmitter.contents = newemitterImg;
newEmitter.name = #"New Emitter";
newEmitter.color = [[UIColor colorWithRed:0.50 green:0.00 blue:1.00 alpha:1.00] CGColor];
newEmitter.scaleRange = 4.178236607142859;
newEmitter.lifetimeRange = 1.6;
newEmitter.greenRange = -2.775558e-17;
newEmitter.birthRate = 40;
newEmitter.emissionRange = -6.283185306666667;
newEmitter.scale = 0;
//
// Emitter Cell Chains
//
emitter.emitterCells = [NSArray arrayWithObjects:newEmitter, nil];
And here is where I am testing the color change in this case just bouncing between two different colors:
-(void)changeColor {
if (color == 0) {
color = 1;
NSLog(#"color = 1");
[UIView animateWithDuration:1.5 delay:0 options:0 animations:^{
newEmitter.color = [[UIColor colorWithRed:0.50 green:0.00 blue:1.00 alpha:1.00] CGColor];
} completion:^(BOOL finished) {[self performSelector:#selector(changeColor) withObject:nil afterDelay:2];}];
} else {
color = 0;
NSLog(#"color = 0");
[UIView animateWithDuration:1.5 delay:0 options:0 animations:^{
newEmitter.color = [[UIColor colorWithRed:1.00 green:0.50 blue:0.10 alpha:1.00] CGColor];
} completion:^(BOOL finished) {[self performSelector:#selector(changeColor) withObject:nil afterDelay:2];}];
}
}
However, when I run this the color never changes. Have I misunderstood the nature of "Animatable" here, or do I just need to go about it differently for a CAEmitterCell?
CAEmitterCells are, in fact, different. To get animations working on them, you need to take these steps:
1.Assign a name to your CAEmitterCell, e.g.:
newEmitter.name = #"fire";
2.Access the animation property for this emitter through the CAEmitterLayer instance:
//Set first before doing CABasicAnimation so it sticks
newEmitter.redSpeed = 1.0;
//Access the property with this key path format: #"emitterCells.<name>.<property>"
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"emitterCells.fire.redSpeed"];
anim.fromValue = #(0.0);
anim.toValue = #(1.0);
anim.duration = 1.5;
anim.fillMode = kCAFillModeForwards;
[emitter addAnimation:anim forKey:#"emitterAnim"];
Try this:
[newEmitter.emitterCells[0] setColor:[[UIColor yellowColor] CGColor]];
You can use those properties to animate emiter color.
newEmitter.redSpeed = 1.0;
newEmitter.greenSpeed = 1.0;
newEmitter.blueSpeed = 1.0;

Fitting View Frame around Scaled CALayer

In the following method, I'm simply enlarging a bunch of CAShapeLayers which are attached to my views layer property by using CATransform3DMakeScale. I'm able to enlarge the shape layers correctly, but am having a tough time getting the view frame to enlarge and fit around the graphic produced by the shape layers like it should. Everything is the same size, ie the view frame is the same size as all of the shape layers.
Anyone have any suggestions on how to fix this? I've tried altering the views transform property as well as the views layer transform property. Not sure what I'm missing here.
- (void) setSize:(CGSize)size
{
CATransform3D transform = CATransform3DMakeScale(size.width / (self.graphic.initialSize.width), size.height / (self.graphic.initialSize.height), 1);
self.layer.sublayerTransform = transform;
self.frame = CGRectMake(0, 0, size.width, size.height);
self.graphic.size = CGSizeMake(size.width, size.height);
}
Also for reference, here is how I am setting up the views layer:
- (id)initWithGraphic:(Graphic*)graphic
{
self = [super initWithFrame:CGRectZero];
if (self)
{
self.backgroundColor = [UIColor clearColor];
_graphic = [graphic retain];
self.frame = CGRectMake(0,0, _graphic.initialSize.width, _graphic.initialSize.height);
self.layer.shouldRasterize = YES;
for (int i = 0; i < [_graphic.shapeLayers count]; i++)
{
[self.layer addSublayer:[_graphic.shapeLayers objectAtIndex:i]];
}
}
return self;
}
and here is how I'm setting up one of the shape layers:
CAShapeLayer *outlineShapeLayer = [[CAShapeLayer alloc] init];
outlineShapeLayer.anchorPoint = CGPointMake(0, 0);
outlineShapeLayer.fillColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1].CGColor;
outlineShapeLayer.bounds = shapeLayerFrame;
outlineShapeLayer.mutablePath = mutablePath;
I had to make it so my views layer also had it's anchorPoint and position set up to match my CAShapeLayers and then it worked:
self.layer.anchorPoint = CGPointMake(0, 0);
self.layer.position = CGPointMake(0, 0);

Jerky scroll with UIButton.layer.shadowColor

I got a UITableView header with lots of buttons.
I use this to create a shadow on the buttons:
Buttona.layer.shadowColor = [UIColor blackColor].CGColor;
Buttona.layer.shadowOpacity = 0.7f;
Buttona.layer.shadowOffset = CGSizeMake(10.0f, 10.0f);
Buttona.layer.shadowRadius = 7.0f;
Buttona.layer.masksToBounds = NO;
Buttonb.layer.shadowColor = [UIColor blackColor].CGColor;
Buttonb.layer.shadowOpacity = 0.7f;
Buttonb.layer.shadowOffset = CGSizeMake(2.0f, 3.0f);
Buttonb.layer.shadowRadius = 2.0f;
Buttonb.layer.masksToBounds = NO;
... and so on for Buttonc to Buttonf.
The scroll on the table becomes jerky with all theses buttons.
Should I get rid of the effect and just Photoshop the buttons with the shadow, or am I doing something wrong here?
Thanks in advance.
I had the same problem and the solution is
[view.layer setShadowPath:[[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)] CGPath]];

how to animate the uilabel view in such a way that it should keep moving from right side of the screen towards left , in obj c

how to animate the uilabel view in such a way that it should keep moving from right side of the screen towards left ,
i have used the folloiwing code but it didnt work
UILabel * lbl =[UILabel alloc]init];
CALayer *cloud = [CALayer layer];
cloud.contents = lbl.text;
cloud.bounds = CGRectMake(0, 40, 100, 30);
cloud.position = CGPointMake(-45 ,30);
//cloud.position = CGPointMake(self.view.bounds.size.width / 2,cloudImage.size.height / 2);
[self.view.layer addSublayer:cloud];
CGPoint startPt = CGPointMake(self.view.bounds.size.width + cloud.bounds.size.width / 2,
cloud.position.y);
CGPoint endPt = CGPointMake(cloud.bounds.size.width / -2,
cloud.position.y);
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"position"];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim.fromValue = [NSValue valueWithCGPoint:startPt];
anim.toValue = [NSValue valueWithCGPoint:endPt];
anim.repeatCount = 1;
anim.duration = 5.0;
[cloud addAnimation:anim forKey:#"position"];
It's a lot easier if you can use animateWithDuration in ios4
UILabel *label = //new label
[UIView animateWithDuration:1.0 animations:^{
label.frame = //new frame
}];
You can do it like this:
UILabel *label = [[UILabel alloc] initWithFrame:theRect];
[self.view addSubview:label];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseIn
animations:^{label.bounds = targetRect;}
completion:^(BOOL finished) { /* completion stuff */}];
There are more animate methods that take less parameters. You find them in the UIView documentation.