最近项目中遇到了一个需求,在做车况的检查动画时,开始以为时非常简单的动画通过UIBezierPath几句代码就搞定的事,最后UI出来的时候 才发现事情要稍微麻烦一点点,就因为UI给的图是水平的平角 如果用系统的直接画图是实现不了这个效果的,没办法那就只有麻烦点计算下撸呗,先看下效果图:
其实要做这个也不是很麻烦,做完之后其实就其中的画弧角度需要运动三角函数关系计算下角度问题。其次是车况分数的渐变效果是根据分数渐变最后一部分小弧度的。
主要代码部分:
其中角度offsetAngle就是偏移的角度:如图 具体的就不阐述了。
#define DEGREES_TO_RADIANS(degrees) ((degrees)*M_PI)/180
#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0/ M_PI))
#define STARTANGLE(radians)180-radians
#define ENDANGLE(radians)(360-(90-radians)*2)
//外层
-(void)drowOuter
{
doubleoffsetAngle = [selfcalculateAngleValueRadius:self.circleRadiusdifRadius:1];
UIBezierPath*path = [UIBezierPathbezierPath];
[pathaddArcWithCenter:CGPointMake(_centerCircleX,_centerCircleY)radius:self.circleRadiusstartAngle:DEGREES_TO_RADIANS(STARTANGLE(_endAngle))endAngle:DEGREES_TO_RADIANS(_startAngle+ENDANGLE(_endAngle))clockwise:YES];
[pathaddArcWithCenter:CGPointMake(_centerCircleX,_centerCircleY)radius:self.circleRadius-2startAngle:DEGREES_TO_RADIANS(STARTANGLE(offsetAngle)+ENDANGLE(offsetAngle))endAngle:DEGREES_TO_RADIANS(180-offsetAngle)clockwise:NO];
[pathclosePath];
CAShapeLayer*arc = [CAShapeLayerlayer];
arc.path= path.CGPath;
arc.fillColor=self.fillColor.CGColor;
arc.strokeColor=self.fillColor.CGColor;
[self.layeraddSublayer:arc];
}
//内层背景
-(void)drowBottom
{
UIBezierPath*path = [selfgetProgressPath:1.0];
CAShapeLayer*arc = [CAShapeLayerlayer];
arc.path= path.CGPath;
arc.fillColor=self.fillColor.CGColor;
arc.strokeColor=self.fillColor.CGColor;
[self.layeraddSublayer:arc];
}
//内层进度
-(void)drowProgress
{
UIBezierPath*path = [selfgetProgressPath:0.0];
CAShapeLayer*arc = [CAShapeLayerlayer];
_progressLayer= arc;
arc.path= path.CGPath;
CAGradientLayer*gradientLayer = [CAGradientLayerlayer];
_gradientLayer= gradientLayer;
gradientLayer.frame=self.frame;
gradientLayer.colors=@[(__bridgeid)[UIColorcolorWithWhite:1alpha:0.4].CGColor,(__bridgeid)[UIColorcolorWithWhite:1alpha:1].CGColor];
gradientLayer.startPoint=CGPointMake(0,0.5);
gradientLayer.endPoint=CGPointMake(1,0.5);
CALayer*lay = [CALayerlayer];
[layaddSublayer:gradientLayer];
lay.mask=_progressLayer;
[self.layeraddSublayer:lay];
}
-(UIBezierPath*)getProgressPath:(CGFloat)progress
{
UIBezierPath*path = [UIBezierPathbezierPath];
[pathsetLineWidth:1.0];
[pathaddArcWithCenter:CGPointMake(_centerCircleX,_centerCircleY)radius:_progressRadiusstartAngle:DEGREES_TO_RADIANS(STARTANGLE(_offsetOutAngle))endAngle:DEGREES_TO_RADIANS(180-_offsetOutAngle+ENDANGLE(_offsetOutAngle)*progress)clockwise:YES];
[pathaddArcWithCenter:CGPointMake(_centerCircleX,_centerCircleY)radius:_progressRadius-7startAngle:DEGREES_TO_RADIANS(STARTANGLE(_offsetAngle)+ENDANGLE(_offsetAngle)*progress)endAngle:DEGREES_TO_RADIANS(180-_offsetAngle)clockwise:NO];
returnpath;
}
//计算角度
-(double)calculateAngleValueRadius:(CGFloat)radius difRadius:(CGFloat)difRadius
{
doubleoffsetAngle =0.0;
//double x1 = self.width/2 + radius*cos(DEGREES_TO_RADIANS(_startAngle));
doubley1 =_centerCircleY+ radius*sin(DEGREES_TO_RADIANS(_startAngle));
doublevalueA =fabs(sqrt((radius-difRadius)*(radius-difRadius)-((y1-_centerCircleY)*(y1-_centerCircleY))) -_centerCircleX);
//利用余弦定理求角弧度
doublefa = radius*sin(DEGREES_TO_RADIANS(_startAngle));
doublefb = radius-difRadius;
doublefc = (_centerCircleX- valueA);
double offsetRadian =acos((fb*fb+fc*fc-fa*fa)/(2*fb*fc));
offsetAngle =RADIANS_TO_DEGREES(offsetRadian);
return offsetAngle;
}
渐变部分代码 由于和进度有关系所以用到了比例:
floatvalue = [currentProgressfloatValue];
UIBezierPath*path = [selfgetProgressPath:value];
_progressLayer.path= path.CGPath;
_gradientLayer.locations=@[@(value*0.5),@(value*0.75)];
intvalueNum =round(value*100.0);
[selfsetValueForLable:@(valueNum)];
if(valueNum >=0&& valueNum <60) {
self.backgroundColor=MAIN_RED_COLOR;
}elseif(valueNum >=60&& valueNum <80){
self.backgroundColor=MAIN_ORANGE_COLOR;
}else{
self.backgroundColor=MAIN_GREEN_COLOR;
}
为了数字联动和弧度动画效果用到了定时器其中的具体代码和效果图见GitHub地址:https://github.com/loveWang/WCarProgress.git