IOS 圆形进度条

//
//  CCProgressView.h
//  Demo
//
//  Created by leao on 2017/8/7.
//  Copyright ? 2017年 zaodao. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, CCProgressViewStyle) {
    CCProgressViewStyleCircle,                                          // 圆形进度条
    CCProgressViewStyleBar,                                             // 条形进度条
    CCProgressViewStyleDefault = CCProgressViewStyleCircle,
};

@interface CCProgressView : UIView
@property(nonatomic, assign, setter=setProgress:) CGFloat progress;     // 0.0 ~ 1.0

@property(nonatomic, assign) CCProgressViewStyle progressViewStyle;     // 进度条style
@property(nonatomic, strong) UIColor *trackTintColor;                   // 进度条背景色
@property(nonatomic, strong) UIColor *progressTintColor;                // 进度条颜色
@property(nonatomic, strong) UIColor *progressFullTintColor;            // 进度完成时progressTint的颜色
@property(nonatomic, assign) CGFloat lineWidth;                         // 绘制progress宽度  default: 10
@property(nonatomic, assign) CGFloat trackerWidth;                         // 绘制progress宽度  default: 10

// CCProgressViewStyleCircle 有效
@property(nonatomic, strong) UIColor *fillColor;                // 中心颜色
@property(nonatomic, assign) BOOL clockwise;                    // 是否是顺时针 default: YES
@property(nonatomic, assign) CGFloat startAngle;                // 进度条开始angle, default: -M_PI/2.0
@property (nonatomic, strong) UIButton *centerBtn; // 记录进度的Label
@property (nonatomic, strong) UIColor *labelbackgroundColor; // Label的背景色 默认clearColor
@property (nonatomic, strong) UIColor *textColor; // Label的字体颜色 默认黑色
@property (nonatomic, strong) UIFont  *textFont; // Label的字体大小 默认15

- (void)setProgress:(CGFloat)progress;
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end
//
//  CCProgressView.m
//  Demo
//
//  Created by leao on 2017/8/7.
//  Copyright ? 2017年 zaodao. All rights reserved.
//

#import "CCProgressView.h"
#import <pop/POP.h>
#import <objc/runtime.h>
#import <ReactiveCocoa/ReactiveCocoa.h>

#define kCCProgressFillColor                [UIColor clearColor]
#define kCCProgressTintColor                RGBCOLOR(214, 88, 45)
#define kCCTrackTintColor                   RGBCOLOR(243, 212, 187)
#define PROGRESS_WIDTH                      self.frame.size.width
#define PROGRESS_HEIGHT                     self.frame.size.height

#define kAnimTimeInterval 2

@interface CCProgressView ()

@property(nonatomic, strong) CAShapeLayer *trackLayer;
@property(nonatomic, strong) CAShapeLayer *progressLayer;

@end
@implementation CCProgressView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initSubviews];
    }
    return self;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self initSubviews];
    }
    return self;
}

#pragma mark - private
- (void)initSubviews
{
    _progressViewStyle = CCProgressViewStyleDefault;
    _progressTintColor = kCCProgressTintColor;
    _trackTintColor = kCCTrackTintColor;
    _lineWidth = 10;
    _trackerWidth = 10;

    _fillColor = kCCProgressFillColor;
    _clockwise = YES;
    _startAngle = - M_PI / 2.0;

    self.backgroundColor = [UIColor clearColor];

    self.trackLayer = [CAShapeLayer layer];
    self.trackLayer.lineCap = kCALineCapButt;
    self.trackLayer.lineJoin = kCALineCapButt;
    self.trackLayer.lineWidth = _lineWidth;
    self.trackLayer.fillColor = nil;
    self.trackLayer.strokeColor = _trackTintColor.CGColor;
    self.trackLayer.frame = self.bounds;
    [self.layer addSublayer:self.trackLayer];

    self.progressLayer = [CAShapeLayer layer];
    self.progressLayer.lineCap = kCALineCapButt;
    self.progressLayer.lineJoin = kCALineCapButt;
    self.progressLayer.lineWidth = _trackerWidth;
    self.progressLayer.fillColor = _fillColor.CGColor;
    self.progressLayer.strokeColor = _progressTintColor.CGColor;
    self.progressLayer.frame = self.bounds;
    [self.layer addSublayer:self.progressLayer];

    self.progressLayer.strokeEnd = 0.0;

    [self addSubview:self.centerBtn];
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    [self updateLayerPath];
}

#pragma mark - private

- (UIButton *)centerBtn
{
    if(!_centerBtn)
    {
        _centerBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, PROGRESS_WIDTH - 14, PROGRESS_HEIGHT - 14)];
        _centerBtn.center = CGPointMake(PROGRESS_WIDTH/2, PROGRESS_HEIGHT/2);
        _centerBtn.titleLabel.textAlignment = NSTextAlignmentCenter;
        _centerBtn.layer.cornerRadius = _centerBtn.width/2;
        _centerBtn.backgroundColor = RGBCOLOR(246, 227, 204);
        _centerBtn.titleLabel.adjustsFontSizeToFitWidth = YES;
        _centerBtn.userInteractionEnabled = NO;
        _centerBtn.layer.masksToBounds = YES;
    }
    return _centerBtn;
}

- (void)updateLayerPath
{
    if (_progressViewStyle == CCProgressViewStyleCircle) {
        self.trackLayer.frame = self.bounds;
        self.progressLayer.frame = self.bounds;

        CGFloat radius = CGRectGetWidth(self.frame) > CGRectGetHeight(self.frame) ?
        (CGRectGetHeight(self.frame) - _lineWidth) / 2.0 : (CGRectGetWidth(self.frame) - _lineWidth) / 2.0;
        UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:self.progressLayer.position radius:radius startAngle:_startAngle endAngle:_clockwise ? _startAngle + 2 * M_PI : _startAngle - 2 * M_PI clockwise:_clockwise];
        self.trackLayer.path = bezierPath.CGPath;
        self.progressLayer.path = bezierPath.CGPath;
    } else {
        self.trackLayer.frame = CGRectMake(0, (CGRectGetHeight(self.frame) - _lineWidth) / 2.0, CGRectGetWidth(self.frame), _lineWidth);
        self.progressLayer.frame = self.trackLayer.frame;

        UIBezierPath *bezierPath = [UIBezierPath bezierPath];
        [bezierPath moveToPoint:CGPointMake(0, self.progressLayer.position.y)];
        [bezierPath addLineToPoint:CGPointMake(CGRectGetWidth(self.frame), self.progressLayer.position.y)];
        self.trackLayer.path = bezierPath.CGPath;
        self.progressLayer.path = bezierPath.CGPath;
    }
}

#pragma mark - setter
- (void)setTrackTintColor:(UIColor *)trackTintColor
{
    _trackTintColor = trackTintColor;
    self.trackLayer.strokeColor = trackTintColor.CGColor;
}

- (void)setProgressTintColor:(UIColor *)progressTintColor
{
    _progressTintColor = progressTintColor;
    self.progressLayer.strokeColor = progressTintColor.CGColor;
}

- (void)setProgressFullTintColor:(UIColor *)progressFullTintColor
{
    _progressFullTintColor = progressFullTintColor;
    if (self.progressLayer.strokeEnd >= 1.0) {
        self.progressLayer.strokeEnd = 1.0;
        self.progressLayer.strokeColor = _progressFullTintColor.CGColor;
    }
}

- (void)setLineWidth:(CGFloat)lineWidth
{
    _lineWidth = lineWidth;
//    self.trackLayer.lineWidth = lineWidth;
    self.progressLayer.lineWidth = lineWidth;
    if (_progressViewStyle != CCProgressViewStyleCircle) {
        [self updateLayerPath];
    }
}

- (void)setTrackerWidth:(CGFloat)trackerWidth {
    _trackerWidth = trackerWidth;
    self.trackLayer.lineWidth = _trackerWidth;
    if (_progressViewStyle != CCProgressViewStyleCircle) {
        [self updateLayerPath];
    }
}

#pragma mark - setter (CCProgressViewStyleCircle)
- (void)setFillColor:(UIColor *)fillColor
{
    _fillColor = fillColor;
    self.progressLayer.fillColor = fillColor.CGColor;
}

- (void)setClockwise:(BOOL)clockwise
{
    _clockwise = clockwise;
    [self updateLayerPath];
}

- (void)setStartAngle:(CGFloat)startAngle
{
    _startAngle = startAngle;
    [self updateLayerPath];
}

- (void)setProgress:(CGFloat)progress
{
    [self setProgress:progress animated:NO];
}

- (void)setProgress:(CGFloat)progress animated:(BOOL)animated
{
    if (animated) {  // 这里的动画可以直接使用CABasicAnimation
        POPBasicAnimation *basicAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
        if (basicAnim) {
            basicAnim.duration = kAnimTimeInterval;
            basicAnim.toValue = @(progress);
        } else {
            basicAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
            basicAnim.fromValue = @(self.progressLayer.strokeEnd);
            basicAnim.toValue = @(progress);
            basicAnim.duration = 4 * kAnimTimeInterval;
            basicAnim.removedOnCompletion = YES;
        }
        @weakify(self);
        basicAnim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
            @strongify(self);
            POPPropertyAnimation *basicAnim = (POPPropertyAnimation *)anim;
            self.progressLayer.strokeEnd = [basicAnim.toValue doubleValue];
            if (self.progressLayer.strokeEnd >= 1.0 && _progressFullTintColor) {
                self.progressLayer.strokeEnd = 1.0;
                self.progressLayer.strokeColor = _progressFullTintColor.CGColor;
            }
        };
        [self.progressLayer pop_addAnimation:basicAnim forKey:kPOPShapeLayerStrokeEnd];
    } else {
        self.progressLayer.strokeEnd = progress;
        if (self.progressLayer.strokeEnd >= 1.0 && _progressFullTintColor) {
            self.progressLayer.strokeEnd = 1.0;
            self.progressLayer.strokeColor = _progressFullTintColor.CGColor;
        }
    }
}

@end
时间: 2024-10-14 18:53:08

IOS 圆形进度条的相关文章

iOS 图片加载 圆形进度条

项目中有加载网络图片的需求,加一个加载的进度条会提高用户体验,网络不好的时候会清晰的看到图片加载的进度,比让用户看着满屏幕空白好.下面是我们项目自己封装的圆形进度条,分享给大家. 其实实现原理很简单,只是根据图片加载的进度来绘制一个圆. 先来看.h文件,需要一个进度的属性和进度条展示位置的方法: @property (nonatomic, assign) CGFloat progress; +(HMProgressView *)showHMProgressView:(UIView *)paren

iOS开发笔记-根据frame大小动态调整fontSize的自适应文本及圆形进度条控件的实现

最近同样是新App,设计稿里出现一种圆形进度条的设计,如下: 想了想,圆形进度条实现起来不难,但是其中显示百分比的文本确需要自适应,虽然可以使用时自己设定文本字体的大小,但是这样显得很麻烦,也很low. 查了一圈,目前实现的自适应UILabel,都是根据font大小动态调整frame的size,并不能满足我们的需求.  那么问题来了 如何实现一种能够根据frame大小自适应调整文本font size的圆形进度条呢? 我的实现思路很简单,首先计算出能够给予UILabel的frame最大尺寸,然后根

利用css3动画和border来实现圆形进度条

最近在学习前端的一些知识,发现border的功能十分强大啊! 首先来看看demo 就是这么一个圆形的进度条,在文本框中输入0-100的数值下面的进度条相应的转到多少 这个主要是利用border,旋转和css动画来实现的,主要思想是利用两个div来互相遮挡border形成的一个只有半圈有颜色的圆形,再利用旋转div的角度来调整显示 上代码: html+css+js(这里引入了jquery) <!DOCTYPE html> <html lang="en"> <

自定义圆形进度条

关于控件呢,我想大家应该都很熟悉了吧,android应用开发MVC架构中,控件担任着至关重要的作用,感觉可以说是基于控件的事件模型人机交互的基础吧.这种特性感觉在wpf开发中体现得更为直接,感兴趣的同学可以去了解一下.而android框架自身就已经给我们提供了很多控件.那么问题来了?为什么有那么多控件可以用,你还要去屑自定义控件呢?是因为大家闲的蛋疼吗?显然不是.个人认为只要有两方面吧,要么是觉得有些原生控件是在是丑得难以忍受(即使是在你已经自定义了他的shape,圆角,selector等一系列

Android自定义View——圆形进度条式按钮

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

Html5基于SVG的扁平风格圆形进度条javascript插件教程

一.使用方法 使用该圆形进度条需要引入circleDonutChart.js文件. <script type="text/javascript" src="circleDonutChart.js"></script> 二.Html结构 你可以使用一个空的<div>元素来制作圆形进度条. <div id="example1"></div> 三.初始化插件 要制作圆形进度条,可以使用下面的方

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View

CAShapeLayer实现圆形进度条效果

一.CAShapeLayer简介: 1.CAShapeLayer继承至CALayer,可以使用CALayer的所有属性值 2.CAShapeLayer需要与贝塞尔曲线配合使用才有意义 3.使用CAShapeLayer与贝塞尔曲线可以实现不在view的drawRect方法中画出一些想要的图形 4.CAShapeLayer属于CoreAnimation框架,其动画渲染直接提交到手机的GPU当中,相较于view的drawRect方法使用CPU渲染而言,其效率极高,能大大优化内存使用情况 五角星动画 #

WPF 实现圆形进度条

项目中用到圆形进度条,首先就想到使用 ProgressBar 扩展一个,在园子里找到 迷途的小榔头 给出的思路和部分代码,自己加以实现.在此感谢 迷途的小榔头! 进度小于60显示红色,大于60则显示绿色.效果如下: 基本思路: 本质上是一个进度条,只是外观有别于矩形进度条,所以需要修改ProgressBar的ControlTemplate. 进度条部分实际是一个扇形,用WPF动态绘出(原理参考迷途的小榔头讲解). 要将进度条的值(Value依赖属性)转换为进度条,需要一个Converter. 根