ios - UIBezierPath & CAShapeLayer initial animation jump -
i built company: https://github.com/busycm/bzystroketimer , during course of building, noticed interesting "bug" can't seem mitigate when using uibezierpath
. right when animation starts, path jumps number of pixels forward (or backwards depending if it's counterclockwise) instead of starting smooth, incremental animation. , found that's interesting how path jumps forward value of line width cashaperlayer
.
so example, if bezier path starts off @ cgrectgetmidx(self.bounds)
, line 35, animation starts cgrectgetmidx(self.bounds)+35
, larger line width, more noticeable jump is. there way rid of path smoothly animate out start point?
here's picture of first frame. looks after animation starts.
then when resume animation , pause again, distance moved 1/100th of distance see in picture.
here's bezier path code:
- (uibezierpath *)generatepathwithxinset:(cgfloat)dx withyinset:(cgfloat)dy clockwise:(bool)clockwise{ uibezierpath *path = [uibezierpath bezierpath]; [path movetopoint:cgpointmake(cgrectgetmidx(self.bounds)+dx/2, dy/2)]; [path addlinetopoint:cgpointmake(cgrectgetmaxx(self.bounds)-dx/2, dy/2)]; [path addlinetopoint:cgpointmake(cgrectgetmaxx(self.bounds)-dx/2, cgrectgetmaxy(self.bounds)-dy/2)]; [path addlinetopoint:cgpointmake(dx/2, cgrectgetmaxy(self.bounds)-dy/2)]; [path addlinetopoint:cgpointmake(dx/2, dy/2)]; [path closepath]; return clockwise ? path : [path bezierpathbyreversingpath]; }
here's animation code:
cabasicanimation *wind = [self generateanimationwithduration:self.duration == 0 ? kdefaultduration : self.duration fromvalue:@(self.shapelayer.strokestart) tovalue:@(self.shapelayer.strokeend) withkeypath:keypath withfillmode:kcafillmodeforwards]; wind.timingfunction = [camediatimingfunction functionwithname:self.timingfunction]; wind.removedoncompletion = no; self.shapelayer.path = [self generatepathwithxinset:self.linewidth withyinset:self.linewidth clockwise:self.clockwise].cgpath; [self.shapelayer addanimation:wind forkey:@"strokeendanimation"];
and here's how construct cashapelayer
.
- (cashapelayer *)shapelayer { return !_shapelayer ? _shapelayer = ({ cashapelayer *layer = [cashapelayer layer]; layer.linewidth = kdefaultlinewidth; layer.fillcolor = uicolor.clearcolor.cgcolor; layer.strokecolor = [uicolor blackcolor].cgcolor; layer.linecap = kcalinecapsquare; layer.frame = self.bounds; layer.strokestart = 0; layer.strokeend = 1; layer; }) : _shapelayer; }
i think what's happening here that, in frame of animation, drawing line consists of single point. since line has thickness associated it, , line cap type kcalinecapsquare
, that'll rendered square height , width equal line width.
you can think of if drawing line square marker, , going drag midpoint of marker goes through every point in curve specified. first point in line, it's if marker touches down @ point, leaving square behind.
here's visual representation different line cap types make more intuitive. should change line cap style kcalinecapbutt
.
sidenote: after make change, in line of code
[path movetopoint:cgpointmake(cgrectgetmidx(self.bounds)+dx/2, dy/2)];
you don't have offset x
coordinate dx/2
anymore.
Comments
Post a Comment