I am animating a CALayer to move and for some reason I keep getting these thin white lines all across the screen... it's not my device I can assure you here is how I set up the CALayer:
dodgelayer=nil;
dodgelayer= [CALayer layer];
dodgelayer.backgroundColor = [UIColor blueColor].CGColor;
dodgelayer.frame = CGRectMake(190, 80, 50, 50);
dodgelayer.borderColor = [UIColor whiteColor].CGColor;
dodgelayer.borderWidth = 2.0;
dodgelayer.cornerRadius = 50.0;
and how I animate it:
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
values = [NSArray arrayWithObjects:[NSValue valueWithCGPoint: CGPointMake(aLayer.frame.origin.x+25,aLayer.frame.origin.y+25)], [NSValue valueWithCGPoint: CGPointMake(point.x,point.y)], nil];
[anim setValues:values];
[anim setDuration:0.7];
anim.removedOnCompletion=NO;
anim.fillMode = kCAFillModeForwards;
anim.timingFunction=[CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut];
sublayer.shouldRasterize=YES;
[sublayer addAnimation:anim forKey:#"position"];
I honestly have no idea what is making these thing white lines appear, but I can tell you that they appear during animations... im stumped on this one any help would be appreciated
I just bumped into this problem myself.
The cause is the shouldResterize = YES.
Before calling this, you should set
sublayer.rasterizationScale = [[UIScreen mainScreen] scale];
and the lines will go away.
Related
I'm working on implementing a (very) simple screensaver using the Screensaver framework in OS X 10.10. Positioning on the center of the screen and displaying a two-line text works without problem, but setting the alignment to NSCenterTextAlignment somehow doesn't (the text is always displayed left-aligned).
- (void)animateOneFrame
{
// calculate font size based on screen
NSSize size = [self bounds].size;
CGFloat fontsize = size.height / 11;
// set text
NSMutableParagraphStyle *centredStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[centredStyle setAlignment:NSCenterTextAlignment];
NSDictionary *textAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSFont fontWithName:#"Futura" size:fontsize], NSFontAttributeName,
[NSColor orangeColor], NSForegroundColorAttributeName,
centredStyle, NSParagraphStyleAttributeName,
nil];
NSString *theText = #"Simple text spanning\ntwo lines";
// position text on screen
NSRect boundingRect = [theText boundingRectWithSize:size options:0 attributes:textAttributes];
NSPoint point = NSMakePoint((size.width - boundingRect.size.width) / 2.0,
(size.height - boundingRect.size.height) / 2.0);
[theText drawAtPoint: point withAttributes: textAttributes];
}
Any pointers on how to solve this are appreciated.
PS: I know that I don't need to put everything into animateOneFrame but for the moment the goal is to get it working at all:-)
I have been playing with CABasicAnimation and CAAnimationGroup today, and I am already in love with it. I have couple of basic animations happening, in which the circle shape shrinks and also downscale to rounded square shape, just like "Voice memo" application in iOS 7.
Below is the code for it.
CABasicAnimation *corner = [CABasicAnimation animationWithKeyPath:#"cornerRadius"];
corner.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
corner.fromValue = [NSNumber numberWithFloat:recordingShape.layer.cornerRadius];
corner.toValue = [NSNumber numberWithFloat:30.0f];
corner.duration = 1.0;
//shrinking - scaling
CABasicAnimation* shrink = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
shrink.toValue = [NSNumber numberWithDouble:0.5];
shrink.duration = 0.5;
// Two animations concurrently so set up CAAnimationGroup
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:0.5];
[group setAnimations:[NSArray arrayWithObjects:shrink, corner, nil]];
// Animate the layer
[[recordingShape layer] addAnimation:group forKey:#"bounceAndFade"];
The animation occurs nicely as expected, but after animation it goes back to its original state as round circle, could anyone guide me as of how can I persist the layer's frame?
Thanks.
Well I Didn't know you could setup a delegate for the CAAnimationGroup group, hence I change the actual cornerRadius and transform at animationDidStop call.
I'm just beginning to use CABasicAnimations. So far it seems to me like the same code won't necessarily work twice on anything. In one particular instance (the solution for which may cure all my ills!) I have made my own (indeterminate) progress indicator. Just a png from PhotoShop which is rotated until a task is done, it's initiated in the view's initWithRect:
CALayer *mainLayer = [CALayer layer];
[myView setWantsLayer:YES];
[myView setLayer:mainLayer];
progressLayer = [CALayer layer];
progressLayer.opacity = 0;
progressLayer.cornerRadius = 0.0;
progressLayer.bounds = CGRectMake(0.0,0.0,50.0,50.0);
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, (id)kCGImageSourceShouldCache,
(id)kCFBooleanTrue, (id)kCGImageSourceShouldAllowFloat,
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
NULL];
CGImageSourceRef isr = CGImageSourceCreateWithURL((__bridge CFURLRef)[[NSBundle mainBundle] URLForImageResource:#"progress_indicator.png"], NULL);
progressLayer.contents = (__bridge id)CGImageSourceCreateImageAtIndex(isr, 0, (__bridge CFDictionaryRef)options);
[mainLayer addSublayer:progressLayer];
And then brought 'onscreen' in a seperate method with:
[CATransaction begin]; //I did this block to snap the indicator to the centre
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
progressLayer.anchorPoint = anchorMiddle; //make sure the png is in the view centre
progressLayer.position = viewCentre;
progressLayer.opacity = 1.0;
[CATransaction setValue:(id)kCFBooleanFalse forKey:kCATransactionDisableActions];
[CATransaction commit];
[CATransaction flush];
CABasicAnimation* rotationAnim = [CABasicAnimation animationWithKeyPath: #"transform.rotation.z"];
rotationAnim.fromValue = [NSNumber numberWithFloat:0.0];
rotationAnim.toValue = [NSNumber numberWithFloat:-2 * M_PI];
rotationAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
rotationAnim.duration = 5;
rotationAnim.repeatCount = 10000;
rotationAnim.removedOnCompletion = NO;
rotationAnim.autoreverses = NO;
[progressLayer addAnimation:rotationAnim forKey:#"transform.rotation.z"];
It often works - but not always. In general CABasicAnimations are driving me slightly mad: I cut & paste code from the internet and sometimes they work sometimes not. My only thought is it's being blocked by other threads. I have a minimum of 4 processes despatched using GCD. Is it just the case that I've blocked up my MacBookPro?
Thanks,
Todd.
Oh dear. I think I just found the problem: I was calling the progress indicator from within a GCD block. I took the call out and into the main body of the code (as it were) and all seems good now....
i have a view with rounded corners.
I want to make it rounded just at the two bottom corners of the view.
How can i do that?
This is my code that makes the rounded corners for the view:
CALayer *myLayer = moreInfoView.layer;
[myLayer setCornerRadius:20.0];
[view.layer setMasksToBounds:YES];
Is it possible?
Thanks!
Round only the UIRectCornerBottomLeft and UIRectCornerBottomRight corners:
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:yourView.bounds
byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight)
cornerRadii:CGSizeMake(5.0, 5.0)];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = yourView.bounds;
layer.path = path.CGPath;
yourView.layer.mask = layer;
Don't think you can do that with the CALayer with ease - you could subclass NSView and make a simple redraw routine. May be easiest to use http://www.cocoadev.com/index.pl?RoundedRectangles as a starting point (after removing the two bezier Paths you do not want to have rounded) and then do a simple:
- (void)drawRect:(CGRect)rect
{
self.layer.masksToBounds = NO;
self.layer.shadowColor = [[UIColor xxxx] CGColor];
self.layer.shadowOffset = CGSizeMake(0,2);
self.layer.shadowRadius = ...
self.layer.shadowOpacity = ...
UIBezierPath *path = [UIBezierPath bezierPathWithPartiallyRoundedRect:rect
byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(20, 20)];
[[UIColor blackColor] setFill or Stroke];
[path stroke or fill];
}
In above link - the second simplified example makes your live easier - as you can simply make two of them 'path lineToPoint: ..'.
this is my drawLayer method in a CALayer's delegate.
it's only responsible for drawing a string with length = 1.
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
CGRect boundingBox = CGContextGetClipBoundingBox(ctx);
NSAttributedString *string = [[NSAttributedString alloc] initWithString:self.letter attributes:[self attrs]];
CGContextSaveGState(ctx);
CGContextSetShadowWithColor(ctx, CGSizeZero, 3.0, CGColorCreateGenericRGB(1.0, 1.0, 0.922, 1.0));
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)string);
CGRect rect = CTLineGetImageBounds(line, ctx);
CGFloat xOffset = CGRectGetMidX(rect);
CGFloat yOffset = CGRectGetMidY(rect);
CGPoint pos = CGPointMake(CGRectGetMidX(boundingBox) - xOffset, CGRectGetMidY(boundingBox)- yOffset);
CGContextSetTextPosition(ctx, pos.x, pos.y);
CTLineDraw(line, ctx);
CGContextRestoreGState(ctx);
}
here's the attributes dictionary:
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSFont fontWithName:#"GillSans-Bold" size:72.0], NSFontAttributeName,
[NSColor blackColor], NSForegroundColorAttributeName,
[NSNumber numberWithFloat:1.0], NSStrokeWidthAttributeName,
[NSColor blackColor], NSStrokeColorAttributeName,
style, NSParagraphStyleAttributeName, nil];
as is, the stroke does not draw, but the fill does.
if i comment out the stroke attributes in the dictionary, the fill draws.
i know this can't be right, but i can't find any reference to this problem.
is this a known issue when drawing text with a delegate ?
as the string is one character, i was following the doc example not using any framesetter machinery, but tried that anyway as a fix attempt without success.
in reading this question's answer, i realized that i needed to be using a negative number for the stroke value. i was thinking of the stroke being applied to the outside of the letter drawn by CTLineDraw, rather then inside the text shape.
i'm answering my own question, in case this should help anyone else with this misunderstanding, as i didn't see the referenced doc covering this.