简介
项目开发过程中,我们通常会遇到这样一类需求。当程序后台进行网络请求数据或者执行耗时的运算时,我们希望能够可视化网络请求的进度,同时,进度条中间显示的是我们产品的logo。我们可以把需求拆分为两个子任务,首先,如何使圆形进度条的加载进度随着数据请求的进度 进行更新,第二,如何添加一个logo图片到圆形进度条中间。下图,大家先直观地感受一下进度条的视觉效果
总体思路
根据需求,附加logo的圆形进度条是由两个子视图组成,分别是圆形进度条,和logo图标。我们自定义一个视图HSProgressCircleView,它由两个字视图组成,HSCircleView和UIImageView,为了增加的灵活性,UIImageView是动态添加的,这样设计的原因是,如果,我们想把image换成label,用来显示进度百分比。这样就很方便了。
圆形进度条
这里,单独放一张图方便大家看清楚圆形进度条的结构。
很清楚的发现,圆形进度条由两部分组成,外沿的灰色边框,内圈的亮绿色的圆弧实时变化着。我们可以通过图层相关的知识,很好的解决问题。
默认情况下,每个视图view都有一个类型为CALayer的属性layer,用于管理与视图相关的动画。view是通过调用方法+(Class)layerClass指定视图的图层类型,因此,可以在自定义view中覆盖方法layerClass指定自己需要的图层类型,本案例中,图层类型是CAShapeLayer,它是CALayer的子类。
默认情况下,一个view视图呈现为方形的,如何让view显示为圆形了?CALayer有一个属性cornerRadius,它控制了视图view的四个角的圆弧化程度,因此,我们可以设置cornerRadius的值为视图宽度的一半,以使得视图显示为圆形。
至于绘制内圈的圆弧,可以组合使用CAShapeLayer的strokeStart,strokeEnd和path属性。下面代码,绘制了视图的内圈圆弧。
const double TWO_M_PI = 2.0 * M_PI;
const double startAngle = -0.25 * TWO_M_PI;
const double endAngle = startAngle + TWO_M_PI;
//配置layer的路径
CGFloat arcRadius=self.frame.size.width/2.0-_borderWidth-_lineWidth/2.0;
UIBezierPath *circlePath=[UIBezierPath bezierPathWithArcCenter:CGPointMake(radiusWidth, radiusWidth) radius:arcRadius startAngle:startAngle endAngle:endAngle clockwise:YES];
self.shapeLayer.path=circlePath.CGPath;
self.shapeLayer.strokeColor=_strokeColor.CGColor;
self.shapeLayer.lineWidth=_lineWidth;
self.shapeLayer.strokeStart=0.0;
有个细节不知道大家有没有注意,这里(红色高亮显色的代码),我们设置圆形路径的半径radius的值为视图宽度的一半 减去 图层边框的宽度 减去图层内圈宽度的一半。
这里,我们定义两个属性borderWidth,和lineWidth。
@property(nonatomic)CGFloat borderWidth;//边框宽度
@property(nonatomic)CGFloat lineWidth;//内圈宽度
borderWidth和lineWidth实现方法如下
- (void)setBorderWidth:(CGFloat)borderWidth{
_borderWidth=borderWidth;
self.shapeLayer.borderWidth=borderWidth;
[self setNeedsLayout];
}
- (void)setLineWidth:(CGFloat)lin