zoukankan      html  css  js  c++  java
  • iOS-贝塞尔画圆动画(圆圈进度百分比)

    目标效果

              

    实现

    新建基于UIview的文件

    .h

    属性

    /** 0 < accuracy < 1 */
    @property (nonatomic,assign) double  accuracy;

    .m

    属性

    ///画圆Layer
    @property (nonatomic,strong) CAShapeLayer *shapeLayer;
    ///底层灰色圆Layer
    @property (nonatomic,strong) CAShapeLayer *shapeFloorLayer;
    ///画圆Path
    @property (nonatomic,strong) UIBezierPath *proPath;
    @property (nonatomic,strong) UILabel * accuracyLabel;
    @property (nonatomic,strong) UICountingLabel * aValueLabel;
    ///圆心
    @property (nonatomic,assign)  CGPoint roundCenter;
    ///圆半径
    @property (nonatomic, assign) CGFloat radius;

    方法

    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            [self setup];
        }
        return self;
    }
    - (void)setup{
        self.backgroundColor = [UIColor whiteColor];
        
        _roundCenter = CGPointMake(self.mqb_width * 0.5, self.mqb_height * 0.5);
        _radius = (self.mqb_width - 20*mqbScale)/2;
        
        
        [self addSubview:self.aValueLabel];
        self.aValueLabel.sd_layout.
        leftSpaceToView(self, 30*mqbScale).
        rightSpaceToView(self, 30*mqbScale).
        centerYIs(_roundCenter.y - 10*mqbScale).
        heightIs(36*mqbScale);
        
        [self addSubview:self.accuracyLabel];
        self.accuracyLabel.sd_layout.
        leftSpaceToView(self, 30*mqbScale).
        rightSpaceToView(self, 30*mqbScale).
        topSpaceToView(self.aValueLabel, 15*mqbScale).
        heightIs(20*mqbScale);
        
        self.accuracyLabel.text = @"百分比";
        
        [self.layer addSublayer:self.shapeFloorLayer];
        [self.layer addSublayer:self.shapeLayer];
    
    }
    
    - (void)setAccuracy:(double)accuracy{
        if (accuracy < 0) {
            _accuracy = 0;
        }else if (accuracy > 1){
            _accuracy = 1;
        }
        else {
            _accuracy = accuracy;
        }
        [self  startAccuracyAnimation];
        [self.aValueLabel countFrom:0 to:(_accuracy*100) withDuration:0.5];
    }
    - (void)startAccuracyAnimation{
        [self.proPath addArcWithCenter:_roundCenter
                                radius:_radius
                            startAngle:3 * M_PI/2
                              endAngle:3 * M_PI/2 + 2 * M_PI * _accuracy
                             clockwise:YES];
        self.shapeLayer.path = self.proPath.CGPath;
        
        /**  动画1
         CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
         animation.fromValue = @(0.0f);
         animation.toValue = @(1.0f);
         animation.duration = 0.5f;
         [self.shapeLayer addAnimation:animation forKey:@"animationStrokeEnd"];
         */
        
        /**  动画2
         POPSpringAnimation *popStrokeEnd = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
         popStrokeEnd.fromValue = @(0.0f);
         popStrokeEnd.toValue = @(1.0f);
         popStrokeEnd.springBounciness = 12;
         popStrokeEnd.springSpeed = 12;
         [self.shapeLayer pop_addAnimation:popStrokeEnd forKey:@"popAnimationStrokeEnd"];
         */
        
        /**  动画3
         POPSpringAnimation *popStrokeEnd = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
         popStrokeEnd.fromValue = @(0.5f);
         popStrokeEnd.toValue = @(1.0f);
         popStrokeEnd.springBounciness = 12;
         popStrokeEnd.springSpeed = 12;
         [self.shapeLayer pop_addAnimation:popStrokeEnd forKey:@"popAnimationStrokeEnd"];
         
         POPSpringAnimation *popStrokeStart = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeStart];
         popStrokeStart.fromValue = @(0.5f);
         popStrokeStart.toValue = @(0.0f);
         popStrokeStart.springBounciness = 12;
         popStrokeStart.springSpeed = 12;
         [self.shapeLayer pop_addAnimation:popStrokeStart forKey:@"popAnimationStartEnd"];
         */
    }
    
    #pragma mark ========== 变量 ==========
    - (UILabel *)accuracyLabel{
        if (!_accuracyLabel) {
            _accuracyLabel = [[UILabel alloc]init];
            _accuracyLabel.font = mqbFont(15.0);
            _accuracyLabel.textColor = [UIColor mqb_colorBlack];
            _accuracyLabel.textAlignment = NSTextAlignmentCenter;
        }
        return _accuracyLabel;
    }
    
    - (UICountingLabel *)aValueLabel{
        if (!_aValueLabel) {
            _aValueLabel = [[UICountingLabel alloc]init];
            _aValueLabel.font = mqbMediumFont(40);
            _aValueLabel.textColor = [UIColor mqb_colorBlack];
            _aValueLabel.textAlignment = NSTextAlignmentCenter;
            _aValueLabel.format = @"%d%%";
        }
        return _aValueLabel;
    }
    - (CAShapeLayer *)shapeFloorLayer{
        if (!_shapeFloorLayer) {
            ///细线条
            UIColor *colorLine = [UIColor mqb_colorSeparatorColor];
            
            
            UIBezierPath *pathLine = [UIBezierPath
                                      bezierPathWithArcCenter:_roundCenter
                                      radius:_radius
                                      startAngle:0
                                      endAngle:2 * M_PI
                                      clockwise:YES];
            _shapeFloorLayer = [CAShapeLayer layer];
            _shapeFloorLayer.fillColor = [UIColor clearColor].CGColor;
            _shapeFloorLayer.strokeColor = colorLine.CGColor;
            _shapeFloorLayer.lineWidth = 2*mqbScale;
            _shapeFloorLayer.path = pathLine.CGPath;
            
        }
        return _shapeFloorLayer;
    }
    - (CAShapeLayer *)shapeLayer{
        if (!_shapeLayer) {
            _shapeLayer = [CAShapeLayer layer];
            _shapeLayer.strokeColor = [UIColor mqb_colorGreen].CGColor;
            _shapeLayer.fillColor = [UIColor clearColor].CGColor;
            _shapeLayer.lineWidth = 10*mqbScale;;
            _shapeLayer.fillRule = kCAFillRuleEvenOdd;
            
            _shapeLayer.lineCap = kCALineCapRound;
        }
        return _shapeLayer;
    }
    
    - (UIBezierPath *)proPath{
        if (!_proPath) {
            _proPath = [[UIBezierPath alloc]init];
            _proPath.lineWidth = 10*mqbScale;
            _proPath.lineCapStyle = kCGLineCapRound;
            _proPath.lineJoinStyle = kCGLineJoinRound;
        }
        return _proPath;
    }

    备注

    代码中用到了SDAutoLayout约束,pop 动画、UICountingLabel 第三方 label 数字动画,UICountingLabel 的 format 原本不支持的百分比格式,如若需要可在源码中 setTextValue 修改:

    修改前

    - (void)setTextValue:(CGFloat)value
    {
        if (self.attributedFormatBlock != nil) {
            self.attributedText = self.attributedFormatBlock(value);
        }
        else if(self.formatBlock != nil)
        {
            self.text = self.formatBlock(value);
        }
        else
        {
            // check if counting with ints - cast to int
            if([self.format rangeOfString:@"%(.*)d" options:NSRegularExpressionSearch].location != NSNotFound ||
               [self.format rangeOfString:@"%(.*)i"].location != NSNotFound)
            {
                self.text = [NSString stringWithFormat:self.format,(int)value];
            }
            else
            {
                self.text = [NSString stringWithFormat:self.format,value];
            }
        }
    }

    修改后

    - (void)setTextValue:(CGFloat)value
    {
        if (self.attributedFormatBlock != nil) {
            self.attributedText = self.attributedFormatBlock(value);
        }
        else if(self.formatBlock != nil)
        {
            self.text = self.formatBlock(value);
        }
        else
        {
            // check if counting with ints - cast to int
            if([self.format rangeOfString:@"%(.*)d%%" options:NSRegularExpressionSearch].location != NSNotFound ||
               [self.format rangeOfString:@"%(.*)i%%"].location != NSNotFound ||
               [self.format rangeOfString:@"%(.*)d" options:NSRegularExpressionSearch].location != NSNotFound ||
               [self.format rangeOfString:@"%(.*)i"].location != NSNotFound)
            {
                self.text = [NSString stringWithFormat:self.format,(int)value];
            }
            else
            {
                self.text = [NSString stringWithFormat:self.format,value];
            }
        }
    }
  • 相关阅读:
    爬虫模块BeautifulSoup
    移动端开发概览【webview和touch事件】
    实战JS正则表达式
    相识HTML5 canvas
    运算符中的一些小技巧
    再看Ajax
    跨终端开发必备概念汇总
    谈谈工作,聊聊生活,想想以后
    页面元素坐标和偏移(clientX/pageX/screenX/layerX/offsetWidth/scrollWidth/clientWidth等)相关整理
    CSS3 Flexbox不迷路指南
  • 原文地址:https://www.cnblogs.com/wangkejia/p/14145138.html
Copyright © 2011-2022 走看看