iOS手把手教你实现圆形进度条

1994 8年前
   <h2>引言</h2>    <p>在做音频项目的时候,播放音频需要显示圆形进度条。今天,教大家如何简单地实现进度条效果!</p>    <p>其实,实现这种效果并不困难。前提是需要了解UIBezierPath,如果未接触过,可以先阅读笔者在很久以前所写过的一篇文章:UIBezierPath精讲</p>    <p>当然,之前在实现 <a href="http://www.open-open.com/lib/view/open1464180193555.html">高级动画-圆形树展开、收起动画</a> 一文中教了大家如何实现渐变圆形进度条,那是采用mask来实现的。</p>    <p>不过,今天教大家做的效果,并没有使用mask,而是直接使用UIBezierPath来实现。</p>    <h2>效果图</h2>    <p><img src="https://simg.open-open.com/show/d8818637351846fa5c91ed167af40fed.png"></p>    <h2>实现原理</h2>    <ol>     <li>第一步:添加背景灰色圆形圈圈,画笔色为灰色,内容色为透明。如此一来,中间的图片就可以看见了</li>     <li>第二步:再添加表示进度的蓝色圆形圈圈,与第一步一样,只是设置画笔颜色为蓝色</li>     <li>第三步:由于bezierpath的圆形起点是M <u>2</u> PI,这与最终的效果不一样,因此需要额外处理一下。所以,将整体的transform旋转-M <u>2</u> PI,这样进度起点就是从12点钟方向开始的了,与效果图一样。但是,整体旋转后,图片就不是正立了,因此需要让图片控件的transform旋转M <u>2</u> PI,这样就是最终的效果了</li>    </ol>    <h2>代码实现</h2>    <p>首先,我们需要新建一个HYBCircleProgressView类,这样才能对整体旋转!</p>    <pre>  <code class="language-objectivec">   @interfaceHYBCircleProgressView: UIView     // 设置图片  - (void)setImageURL:(NSString *)url;  // 更新进度  - (void)updateProgressWithNumber:(NSUInteger)number;     @end     </code></pre>    <p>创建图片:</p>    <pre>  <code class="language-objectivec">   CGRect frame = self.frame;  self.layer.cornerRadius = frame.size.width / 2;  self.layer.masksToBounds = YES;  self.imageView = [[UIImageView alloc]initWithFrame:self.bounds];  [selfaddSubview:self.imageView];     </code></pre>    <h3>第一步:添加灰色圆环</h3>    <p>首先,创建CAShapeLayer对象,然后生成圆形path,并设置画笔颜色为灰色,线宽(圆环的宽)为2,而内容填充色设置为透明色,然后将此层添加到self.layer上:</p>    <pre>  <code class="language-objectivec">   self.outLayer = [CAShapeLayer layer];  CGRect rect = {kLineWidth / 2, kLineWidth / 2,  frame.size.width - kLineWidth, frame.size.height - kLineWidth};  UIBezierPath *path = [UIBezierPathbezierPathWithOvalInRect:rect];  self.outLayer.strokeColor = [UIColor lightGrayColor].CGColor;  self.outLayer.lineWidth = kLineWidth;  self.outLayer.fillColor =  [UIColor clearColor].CGColor;  self.outLayer.lineCap = kCALineCapRound;  self.outLayer.path = path.CGPath;  [self.layeraddSublayer:self.outLayer];     </code></pre>    <h3>第二步:添加蓝色进度圆环</h3>    <p>这一步与第一步相当,只是修改画笔颜色为蓝色而已。所使用的path与第一步的是一样的:</p>    <pre>  <code class="language-objectivec">   self.progressLayer = [CAShapeLayer layer];  self.progressLayer.fillColor = [UIColor clearColor].CGColor;  self.progressLayer.strokeColor = [UIColor blueColor].CGColor;  self.progressLayer.lineWidth = kLineWidth;  self.progressLayer.lineCap = kCALineCapRound;  self.progressLayer.path = path.CGPath;  [self.layeraddSublayer:self.progressLayer];     </code></pre>    <p>到这一步,可以看到的效果是这样的:</p>    <p><img src="https://simg.open-open.com/show/9dddd0c00503c0c50506ffcba506dd41.png"></p>    <p>从效果图可以看到,图片是正立的,但是进度条的起点是从3点钟方向开始的,也就是M <u>2</u> PI开始顺时钟方向变化。可我们希望是从12点钟方向开始顺时钟变化的,那么解决办法就是旋转!看第三步。</p>    <h3>第三步:旋转以调整进度起点</h3>    <p>将整体旋转-90度,使进度起点为12点钟的位置:</p>    <pre>  <code class="language-objectivec">   self.transform = CGAffineTransformMakeRotation(-M_PI_2);     </code></pre>    <p>此时效果是这样的:</p>    <p><img src="https://simg.open-open.com/show/d5f343ea1cf18acec3bcfe3dab5bb05e.png"></p>    <p>图片也跟着旋转了,这不是我们要的效果啊。那么怎么办呢?同样的道理,将图片控件再旋转90度即可:</p>    <pre>  <code class="language-objectivec">   self.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);     </code></pre>    <h2>如何动画调整进度</h2>    <p>调整这个进度,其中就是调整strokeEnd,这个属性是支持隐式动画的:</p>    <pre>  <code class="language-objectivec">   - (void)updateProgressWithNumber:(NSUInteger)number {    [CATransaction begin];    [CATransactionsetAnimationTimingFunction:[CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseIn]];    [CATransactionsetAnimationDuration:0.5];    self.progressLayer.strokeEnd =  number / 100.0;    [CATransaction commit];  }     </code></pre>    <h2>小结</h2>    <p>请大家不要找我要完整的demo,这已经是所有代码了,只不过是没有将构造方式放出来而已!</p>    <p>这里是巧妙地利用旋转来调整起点,又利用贝塞尔曲线来实现所谓地镂空图!看到这里,是不是觉得很简单呢?其实也就那么回事!</p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959673736631066449" rel="nofollow">http://www.henishuo.com/circle-progress-bar/</a></p>    <p> </p>