ios custom ring loading progress

effect

Write pictures described here

#import <UIKit/UIKit.h>

@interface HWCircleView : UIView

@property (nonatomic, assign) CGFloat progress;

//进度条颜色
@property(nonatomic,strong) UIColor *progerssColor;
//进度条背景颜色
@property(nonatomic,strong) UIColor *progerssBackgroundColor;
//进度条的宽度
@property(nonatomic,assign) CGFloat progerWidth;
//进度数据字体大小
@property(nonatomic,assign)CGFloat percentageFontSize;
//进度数字颜色
@property(nonatomic,strong) UIColor *percentFontColor;

@end


#import "HWCircleView.h"

@interface HWCircleView ()

@property (nonatomic, weak) UILabel *cLabel;

@end

@implementation HWCircleView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor clearColor];
        //默认颜色
        self.progerssBackgroundColor=[UIColor lightGrayColor];
        self.progerssColor=[UIColor blueColor];
        self.percentFontColor=[UIColor blueColor];
        //默认进度条宽度
        self.progerWidth=15;
        //默认百分比字体大小
        self.percentageFontSize=22;
        
        //百分比标签
        UILabel *cLabel = [[UILabel alloc] initWithFrame:self.bounds];
        cLabel.font = [UIFont boldSystemFontOfSize:self.percentageFontSize];
        cLabel.textColor = self.percentFontColor;
        cLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:cLabel];
        self.cLabel = cLabel;
    }
    
    return self;
}

- (void)setProgress:(CGFloat)progress
{
    _progress = progress;
    _cLabel.text = [NSString stringWithFormat:@"%d%%", (int)floor(progress * 100)];
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    
    //路径
    UIBezierPath *backgroundPath = [[UIBezierPath alloc] init];
    //线宽
    backgroundPath.lineWidth = self.progerWidth;
    //颜色
    [self.progerssBackgroundColor set];
    //拐角
    backgroundPath.lineCapStyle = kCGLineCapRound;
    backgroundPath.lineJoinStyle = kCGLineJoinRound;
    //半径
    CGFloat radius = (MIN(rect.size.width, rect.size.height) - self.progerWidth) * 0.5;
    //画弧(参数:中心、半径、起始角度(3点钟方向为0)、结束角度、是否顺时针)
    [backgroundPath addArcWithCenter:(CGPoint){rect.size.width * 0.5, rect.size.height * 0.5} radius:radius startAngle:M_PI * 1.5 endAngle:M_PI * 1.5 + M_PI * 2  clockwise:YES];
    //连线
    [backgroundPath stroke];
    
    
    //路径
    UIBezierPath *progressPath = [[UIBezierPath alloc] init];
    //线宽
    progressPath.lineWidth = self.progerWidth;
    //颜色
    [self.progerssColor set];
    //拐角
    progressPath.lineCapStyle = kCGLineCapRound;
    progressPath.lineJoinStyle = kCGLineJoinRound;
    
    //画弧(参数:中心、半径、起始角度(3点钟方向为0)、结束角度、是否顺时针)
    [progressPath addArcWithCenter:(CGPoint){rect.size.width * 0.5, rect.size.height * 0.5} radius:radius startAngle:M_PI * 1.5 endAngle:M_PI * 1.5 + M_PI * 2 * _progress clockwise:YES];
    //连线
    [progressPath stroke];
}

@end


use


@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, weak) HWCircleView *circleView;

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建控件
    HWCircleView *circleView = [[HWCircleView alloc] initWithFrame:CGRectMake(50, 200, 150, 150)];
    [self.view addSubview:circleView];
    self.circleView = circleView;;
    
    //添加定时器
    [self addTimer];
}


- (void)addTimer
{
//创建定时器
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
}

- (void)timerAction
{
    _circleView.progress += 0.01;
   
    if (_circleView.progress >= 1) {
        [self removeTimer];
        NSLog(@"完成");
    }
}

- (void)removeTimer
{
    [_timer invalidate];
    _timer = nil;
}

<hr>

Briefly

###### UIView method of setNeedsDisplay and setNeedsLayout

First two methods are performed asynchronously. The setNeedsDisplay calls automatically call the drawRect method to draw function, so you can get UIGraphicsGetCurrentContext, can be drawn. The setNeedsLayout default call layoutSubViews, you can deal with some of the data sub-view. Summing up the appeal, the setNeedsDisplay easy drawing, while the data out layoutSubViews convenient.

<hr>

layoutSubviews will be called in the following cases

1, init initialization will not trigger layoutSubviews. 2, addSubview trigger layoutSubviews. 3, set the view of Frame trigger layoutSubviews, of course, the premise is changed before and after the frame of the set value. 4, rolling a UIScrollView will trigger layoutSubviews. 5. Turn Screen layoutSubviews event triggers on the parent UIView. 6, changing the size of a UIView when layoutSubviews event will trigger on the parent UIView. 7, directly call setLayoutSubviews.

<hr>

###### drawRect is called in the following cases:

1, if no rect size when UIView initialization, will directly lead to drawRect is not called automatically. After two calls are drawRect method Controller-> loadView, Controller-> viewDidLoad away with, so do not worry about the controller, the View's drawRect began to draw. This will set some values ​​to View in the controller (if View draw when these need to use some variable values).

2, the method is called after sizeToFit call, it is possible to calculate the call sizeToFit size. The system then automatically calls the drawRect: method.

3, by setting the value of UIViewContentModeRedraw contentMode property. It will automatically call each time drawRect set or change the frame of :.

4, direct call setNeedsDisplay, or setNeedsDisplayInRect: trigger drawRect :, but there is a premise that can not be 0 rect. Recommended above 1,2; 3,4 and not advocate

<hr>

###### drawRect method uses Note points:

1, if used UIView drawing, only drawRect: contextRef and obtain the appropriate drawing method. If the acquisition of the acquired invalidate a ref in other methods and can not be used for drawing. drawRect: method does not show the call manually, you must setNeedsDisplay or by calling setNeedsDisplayInRect, let the system automatically tune the method. 2, if used CAlayer drawing, only drawInContext: (similar to the drawRect) rendering, a corresponding method, or delegate the drawing. Is also calling setNeedDisplay and other indirect methods to call more than 3, to real-time drawing, you can not use gestureRecognizer, touchbegan only use other methods to refresh the screen in real time off with setNeedsDisplay

Reproduced in: https: //my.oschina.net/u/2447911/blog/1837967

Guess you like

Origin blog.csdn.net/weixin_34038652/article/details/92291023