Re: sync drawing an ever-increasing path
On 24 Oct, 2012, at 2:37 AM, David Duncan wrote: > On Oct 23, 2012, at 4:37 AM, Roland King wrote: > >> I want to animate the drawing of CGPath in a UIView, so it looks as if it's >> being drawn. I have the UIView, I have the CGPath, I am able to split the >> CGPath at any point from 0 to 100% into that which should be drawn and that >> which shouldn't yet, that's all done, so I can, fairly efficiently, call >> -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] and get a path. > > > You can do this with a CAShapeLayer by animating the strokeEnd property. > Should be very simple to do, although if your path is very complex it may > make more sense to break it into pieces and use multiple shape layers > animated sequentially. > -- > David Duncan > Thanks David, my shape is a bit complex for the strokeEnd property animation, I need to slowly and accurately 'trace' the outline of a path which has multiple elements and contains several closed paths. I already did the math to give me the first x% of the path, efficiently, even splitting any last bezier into a partial, so I'm happy with that bit, just needed to draw these partial and growing paths in sequence. Also I need the path to join correctly as it bends, so drawing it as one path, not different paths on different layers, is optimal. So I made a custom CALayer, gave it a 'percentage' property, made that @dynamic. I set needsDisplayForKey: to return YES for @"percentage" so I get the redraw calls and implemented drawInContext: so that it fetches self.percentage, gets the path for that percentage and draws it. This works. The one thing I had trouble with was getting the animation to start and animate between whatever percentage was and whatever I set it to, the UIViewController just does layer.percentage=1 and expects that to animate. Eventually I found actionForKey: and overrode that method to return a CABasicAnimation .. like this -(id)actionForKey:(NSString*)key { if( [ key isEqualToString:@"percentage" ] ) { CABasicAnimation *anim = [ CABasicAnimation animationWithKeyPath:@"percentage" ]; anim.duration = 2.0f; anim.fromValue = [ self.presentationLayer valueForKey:key ]; // <--- why oh why return anim; } else return [ super actionForKey:key ]; } Two things I don't understand here. First, why do I have to set the fromValue? I found without doing that, I don't get an animation, it just jumps instantly to the final point and draws the whole path? But the documentation for CABasicAnimation says that if fromValue, toValue and byValue are all nil, it should animate from the previous value of keypath to the new value, which is what I want, but doesn't do it. I got stuck on this for ages until I googled up an example showing how to get the current value off the presentation layer and set anim.fromValue, then it works. Secondly, [ self.presentationLayer valueForKey:@"percentage" ] gives me the current value of percentage, which I use for fromValue, fortunately I don't need to set toValue, that it manages to do itself, but if I did want the 'new' value of percentage, how could I get it at that point? I've tried the model layer and everything else I can think of. Is the 'new' value of percentage available at all at the point of actionForKey being called?. Or is actionForKey: the wrong place to return this animation? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: sync drawing an ever-increasing path
On Oct 23, 2012, at 2:44 PM, David Rowland wrote: > There are several paths to be animated. I want each to appear when the user > does some action. It seemed the best to but them in a method called by > drawRect and redraw the view when something changed. Why would the memory > footprint be enlarged? Because simply by implementing -drawRect:, your view will now consume pixelWidth * pixelHeight * 4 bytes of memory, and will need to be rendered onto the screen every time something changes. You could do the exact same thing by just implementing an arbitrarily named method that you call instead of -setNeedsDisplay without the overhead. > > thanks for pointing to didMoveToWindow. > > David > > > > On Oct 23, 2012, at 1:25 PM, David Duncan wrote: > >> >> On Oct 23, 2012, at 12:34 PM, David Rowland wrote: >> >>> This worked for me. When initializing your UIView, add an instance variable >>> "shapeLayer" and do this, >>> >>> shapeLayer = [CAShapeLayer layer]; >>> [[self layer] addSublayer:shapeLayer]; >>> >>> >>> In drawRect, set up your path and do this, >> >> There is no need to do this inside of drawRect. In fact by doing so (unless >> your UIView actually needs to draw something) you've unnecessarily increased >> your memory footprint and reduce the performance to start the animation. >> >> If you want the animation to happen as soon as the view is placed in the >> window, the correct place to do this is inside of -[UIView >> didMoveToWindow:]. Just check that the moved to window is not nil (or >> nothing will happen). >> >>> >>> CABasicAnimation *pathAnimation = [CABasicAnimation >>> animationWithKeyPath:@"strokeEnd"]; >>> pathAnimation.duration = 4.0; >>> pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; >>> pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; >>> [shapeLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; >> >> You can also do this implicitly once the layer is in a layer tree by setting >> the animation duration on the current CATransaction and setting the >> strokeEnd directly. >> >>> >>> >>> >>> That seems to be all that is needed. >>> >>> David >>> >>> >>> >>> >>> On Oct 23, 2012, at 11:37 AM, David Duncan wrote: >>> On Oct 23, 2012, at 4:37 AM, Roland King wrote: > I want to animate the drawing of CGPath in a UIView, so it looks as if > it's being drawn. I have the UIView, I have the CGPath, I am able to > split the CGPath at any point from 0 to 100% into that which should be > drawn and that which shouldn't yet, that's all done, so I can, fairly > efficiently, call -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] > and get a path. You can do this with a CAShapeLayer by animating the strokeEnd property. Should be very simple to do, although if your path is very complex it may make more sense to break it into pieces and use multiple shape layers animated sequentially. -- David Duncan ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/rowlandd%40sbcglobal.net This email sent to rowla...@sbcglobal.net >>> >> >> -- >> David Duncan >> > -- David Duncan ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: sync drawing an ever-increasing path
There are several paths to be animated. I want each to appear when the user does some action. It seemed the best to but them in a method called by drawRect and redraw the view when something changed. Why would the memory footprint be enlarged? thanks for pointing to didMoveToWindow. David On Oct 23, 2012, at 1:25 PM, David Duncan wrote: > > On Oct 23, 2012, at 12:34 PM, David Rowland wrote: > >> This worked for me. When initializing your UIView, add an instance variable >> "shapeLayer" and do this, >> >> shapeLayer = [CAShapeLayer layer]; >> [[self layer] addSublayer:shapeLayer]; >> >> >> In drawRect, set up your path and do this, > > There is no need to do this inside of drawRect. In fact by doing so (unless > your UIView actually needs to draw something) you've unnecessarily increased > your memory footprint and reduce the performance to start the animation. > > If you want the animation to happen as soon as the view is placed in the > window, the correct place to do this is inside of -[UIView didMoveToWindow:]. > Just check that the moved to window is not nil (or nothing will happen). > >> >> CABasicAnimation *pathAnimation = [CABasicAnimation >> animationWithKeyPath:@"strokeEnd"]; >> pathAnimation.duration = 4.0; >> pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; >> pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; >> [shapeLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; > > You can also do this implicitly once the layer is in a layer tree by setting > the animation duration on the current CATransaction and setting the strokeEnd > directly. > >> >> >> >> That seems to be all that is needed. >> >> David >> >> >> >> >> On Oct 23, 2012, at 11:37 AM, David Duncan wrote: >> >>> On Oct 23, 2012, at 4:37 AM, Roland King wrote: >>> I want to animate the drawing of CGPath in a UIView, so it looks as if it's being drawn. I have the UIView, I have the CGPath, I am able to split the CGPath at any point from 0 to 100% into that which should be drawn and that which shouldn't yet, that's all done, so I can, fairly efficiently, call -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] and get a path. >>> >>> >>> You can do this with a CAShapeLayer by animating the strokeEnd property. >>> Should be very simple to do, although if your path is very complex it may >>> make more sense to break it into pieces and use multiple shape layers >>> animated sequentially. >>> -- >>> David Duncan >>> >>> >>> ___ >>> >>> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) >>> >>> Please do not post admin requests or moderator comments to the list. >>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com >>> >>> Help/Unsubscribe/Update your Subscription: >>> https://lists.apple.com/mailman/options/cocoa-dev/rowlandd%40sbcglobal.net >>> >>> This email sent to rowla...@sbcglobal.net >> > > -- > David Duncan > ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: sync drawing an ever-increasing path
On Oct 23, 2012, at 12:34 PM, David Rowland wrote: > This worked for me. When initializing your UIView, add an instance variable > "shapeLayer" and do this, > > shapeLayer = [CAShapeLayer layer]; > [[self layer] addSublayer:shapeLayer]; > > > In drawRect, set up your path and do this, There is no need to do this inside of drawRect. In fact by doing so (unless your UIView actually needs to draw something) you've unnecessarily increased your memory footprint and reduce the performance to start the animation. If you want the animation to happen as soon as the view is placed in the window, the correct place to do this is inside of -[UIView didMoveToWindow:]. Just check that the moved to window is not nil (or nothing will happen). > > CABasicAnimation *pathAnimation = [CABasicAnimation > animationWithKeyPath:@"strokeEnd"]; > pathAnimation.duration = 4.0; > pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; > pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; > [shapeLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; You can also do this implicitly once the layer is in a layer tree by setting the animation duration on the current CATransaction and setting the strokeEnd directly. > > > > That seems to be all that is needed. > > David > > > > > On Oct 23, 2012, at 11:37 AM, David Duncan wrote: > >> On Oct 23, 2012, at 4:37 AM, Roland King wrote: >> >>> I want to animate the drawing of CGPath in a UIView, so it looks as if >>> it's being drawn. I have the UIView, I have the CGPath, I am able to split >>> the CGPath at any point from 0 to 100% into that which should be drawn and >>> that which shouldn't yet, that's all done, so I can, fairly efficiently, >>> call -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] and get a path. >> >> >> You can do this with a CAShapeLayer by animating the strokeEnd property. >> Should be very simple to do, although if your path is very complex it may >> make more sense to break it into pieces and use multiple shape layers >> animated sequentially. >> -- >> David Duncan >> >> >> ___ >> >> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) >> >> Please do not post admin requests or moderator comments to the list. >> Contact the moderators at cocoa-dev-admins(at)lists.apple.com >> >> Help/Unsubscribe/Update your Subscription: >> https://lists.apple.com/mailman/options/cocoa-dev/rowlandd%40sbcglobal.net >> >> This email sent to rowla...@sbcglobal.net > -- David Duncan ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: sync drawing an ever-increasing path
This worked for me. When initializing your UIView, add an instance variable "shapeLayer" and do this, shapeLayer = [CAShapeLayer layer]; [[self layer] addSublayer:shapeLayer]; In drawRect, set up your path and do this, CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; pathAnimation.duration = 4.0; pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; [shapeLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; That seems to be all that is needed. David On Oct 23, 2012, at 11:37 AM, David Duncan wrote: > On Oct 23, 2012, at 4:37 AM, Roland King wrote: > >> I want to animate the drawing of CGPath in a UIView, so it looks as if it's >> being drawn. I have the UIView, I have the CGPath, I am able to split the >> CGPath at any point from 0 to 100% into that which should be drawn and that >> which shouldn't yet, that's all done, so I can, fairly efficiently, call >> -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] and get a path. > > > You can do this with a CAShapeLayer by animating the strokeEnd property. > Should be very simple to do, although if your path is very complex it may > make more sense to break it into pieces and use multiple shape layers > animated sequentially. > -- > David Duncan > > > ___ > > Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) > > Please do not post admin requests or moderator comments to the list. > Contact the moderators at cocoa-dev-admins(at)lists.apple.com > > Help/Unsubscribe/Update your Subscription: > https://lists.apple.com/mailman/options/cocoa-dev/rowlandd%40sbcglobal.net > > This email sent to rowla...@sbcglobal.net ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: sync drawing an ever-increasing path
On Oct 23, 2012, at 4:37 AM, Roland King wrote: > I want to animate the drawing of CGPath in a UIView, so it looks as if it's > being drawn. I have the UIView, I have the CGPath, I am able to split the > CGPath at any point from 0 to 100% into that which should be drawn and that > which shouldn't yet, that's all done, so I can, fairly efficiently, call > -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] and get a path. You can do this with a CAShapeLayer by animating the strokeEnd property. Should be very simple to do, although if your path is very complex it may make more sense to break it into pieces and use multiple shape layers animated sequentially. -- David Duncan ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: sync drawing an ever-increasing path
hmm .. actually it looks like I can TOTALLY use CALayer for this. I need a better book, the one I have doesn't cover this. Hitting google. On 23 Oct, 2012, at 7:37 PM, Roland King wrote: > I want to animate the drawing of CGPath in a UIView, so it looks as if it's > being drawn. I have the UIView, I have the CGPath, I am able to split the > CGPath at any point from 0 to 100% into that which should be drawn and that > which shouldn't yet, that's all done, so I can, fairly efficiently, call > -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] and get a path. > > The idea is to call setNeedsDisplay on the UIView from time to time, then > figure out, when I get my -drawRect call how far through the animation I am, > call fractionalPath: for that fraction of the total animation time, and draw > it. The path isn't that complex, it doesn't take very long to draw and I'm > compositing already-fully-drawn paths into a backing UIImage so there's only > one 'live one' at any time. > > The bit I'm not sure about is how to sync this up with the natural framerate > of the device. I could call setNeedsDisplay on a timer, or with a delay after > each drawRect, but there is surely a better way to do this, is there not? If > I do call setNeedsDisplay a lot, will I only get drawRect at most at the > natural framerate of the device. > > Is there an obvious technology I'm missing? This is a pretty simple way to do > a quick animation of a single path, so OpenGL or anything like that is > massive overkill and I didn't see anything CALayer would give me which would > help, but wondered if I'd missed something there as that does have the > concept of animating a property, even a custom one, between two values and I > wondered if I could hook into that. > ___ > > Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) > > Please do not post admin requests or moderator comments to the list. > Contact the moderators at cocoa-dev-admins(at)lists.apple.com > > Help/Unsubscribe/Update your Subscription: > https://lists.apple.com/mailman/options/cocoa-dev/rols%40rols.org > > This email sent to r...@rols.org ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
sync drawing an ever-increasing path
I want to animate the drawing of CGPath in a UIView, so it looks as if it's being drawn. I have the UIView, I have the CGPath, I am able to split the CGPath at any point from 0 to 100% into that which should be drawn and that which shouldn't yet, that's all done, so I can, fairly efficiently, call -(CGPath)[ myObject fractionalPath:(CGFloat)fraction ] and get a path. The idea is to call setNeedsDisplay on the UIView from time to time, then figure out, when I get my -drawRect call how far through the animation I am, call fractionalPath: for that fraction of the total animation time, and draw it. The path isn't that complex, it doesn't take very long to draw and I'm compositing already-fully-drawn paths into a backing UIImage so there's only one 'live one' at any time. The bit I'm not sure about is how to sync this up with the natural framerate of the device. I could call setNeedsDisplay on a timer, or with a delay after each drawRect, but there is surely a better way to do this, is there not? If I do call setNeedsDisplay a lot, will I only get drawRect at most at the natural framerate of the device. Is there an obvious technology I'm missing? This is a pretty simple way to do a quick animation of a single path, so OpenGL or anything like that is massive overkill and I didn't see anything CALayer would give me which would help, but wondered if I'd missed something there as that does have the concept of animating a property, even a custom one, between two values and I wondered if I could hook into that. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com