iOS仿支付寶芝麻信用儀表盤效果

OPENKING 8年前發布 | 23K 次閱讀 iOS開發 移動開發

自定義View之高仿支付寶芝麻信用分數儀表盤動畫效果

儀表盤動畫效果.jpg

  • 1.圓環上綠點的旋轉

  • 2.分數值及提示語的變化

  • 3.背景色的變化

直接上主要代碼:

1.自定義ZLDashboardView儀表盤文件:

.h 文件:

/**
 *  根據躍動數字
 *
 *  確定百分比
 *  現在的跳動數字——>背景顏色變化
 *
 */

#import <UIKit/UIKit.h>

@interface ZLDashboardView : UIView

@property (nonatomic, strong) UIImage *bgImage;

@property (nonatomic, copy) void(^TimerBlock)(NSInteger);

/**
 *  躍動數字刷新
 *
 */
- (void)refreshJumpNOFromNO:(NSString *)startNO toNO:(NSString *)toNO;

@end

.m 文件

#import "ZLDashboardView.h"
#import "UIView+Extensions.h" 

#define degreesToRadians(x) (M_PI*(x)/180.0) //把角度轉換成PI的方式
static const CGFloat kMarkerRadius = 5.f; // 光標直徑
static const CGFloat kTimerInterval = 0.03;
static const CGFloat kFastProportion = 0.9;

static const NSInteger MaxNumber = 1000;

@interface ZLDashboardView () {
    CGFloat animationTime;
    NSInteger beginNO;
    NSInteger jumpCurrentNO;
    NSInteger endNO;
}

// 百分比 0 - 100 根據躍動數字設置
@property (nonatomic, assign) CGFloat percent;

@property (nonatomic, strong) CAShapeLayer *bottomLayer; // 進度條底色
@property (nonatomic, assign) CGFloat lineWidth; // 弧線寬度

@property (nonatomic, strong) UIImageView *markerImageView; // 光標

@property (nonatomic, strong) UIImageView *bgImageView; // 背景圖片

@property (nonatomic, assign) CGFloat circelRadius; //圓直徑
@property (nonatomic, assign) CGFloat startAngle; // 開始角度
@property (nonatomic, assign) CGFloat endAngle; // 結束角度

@property (nonatomic, strong) UILabel *showLable; // 跳躍數字
@property (nonatomic, strong) UILabel *markedLabel; // 提示語
@property (nonatomic, strong) NSTimer *fastTimer;
@property (nonatomic, strong) NSTimer *slowTimer;

@property (nonatomic, assign) NSInteger intervalNum;

@end

@implementation ZLDashboardView

#pragma mark - Life cycle

- (instancetype)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];

        self.circelRadius = self.frame.size.width - 10.f;
        self.lineWidth = 2.f;
        self.startAngle = -200.f;
        self.endAngle = 20.f;

        // 尺寸需根據圖片進行調整
        self.bgImageView.frame = CGRectMake(6, 6, self.circelRadius, self.circelRadius * 2 / 3);
        self.bgImageView.backgroundColor = [UIColor clearColor];
        [self addSubview:self.bgImageView];

        //添加圓框
        [self setupCircleBg];

        //光標
        [self setupMarkerImageView];

        //添加躍動數字 及 提示語
        [self setupJumpNOView];
    }
    return self;
}


- (void)setupCircleBg {

    // 圓形路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.width / 2, self.height / 2)
                                                        radius:(self.circelRadius - self.lineWidth) / 2
                                                    startAngle:degreesToRadians(self.startAngle)
                                                      endAngle:degreesToRadians(self.endAngle)
                                                     clockwise:YES];

    // 底色
    self.bottomLayer = [CAShapeLayer layer];
    self.bottomLayer.frame = self.bounds;
    self.bottomLayer.fillColor = [[UIColor clearColor] CGColor];
    self.bottomLayer.strokeColor = [[UIColor  colorWithRed:206.f / 256.f green:241.f / 256.f blue:227.f alpha:1.f] CGColor];
    self.bottomLayer.opacity = 0.5;
    self.bottomLayer.lineCap = kCALineCapRound;
    self.bottomLayer.lineWidth = self.lineWidth;
    self.bottomLayer.path = [path CGPath];
    [self.layer addSublayer:self.bottomLayer];

// 240 是用整個弧度的角度之和 |-200| + 20 = 220
//    [self createAnimationWithStartAngle:degreesToRadians(self.startAngle)
//                               endAngle:degreesToRadians(self.startAngle + 220 * 1)];
}

- (void)setupMarkerImageView {
    if (_markerImageView) {
        return;
    }
    _markerImageView = [[UIImageView alloc] init];
    _markerImageView.backgroundColor = [UIColor clearColor];
    _markerImageView.layer.backgroundColor = [UIColor greenColor].CGColor;
    _markerImageView.layer.shadowColor = [UIColor whiteColor].CGColor;
    _markerImageView.layer.shadowOffset = CGSizeMake(0, 0);
    _markerImageView.layer.shadowRadius = kMarkerRadius*0.5;
    _markerImageView.layer.shadowOpacity = 1;
    _markerImageView.layer.masksToBounds = NO;
    self.markerImageView.layer.cornerRadius = self.markerImageView.frame.size.height / 2;
    [self addSubview:self.markerImageView];
    _markerImageView.frame = CGRectMake(-100, self.height, kMarkerRadius, kMarkerRadius);
}

- (void)setupJumpNOView {
    if (_showLable) {
        return;
    }
    CGFloat width = self.circelRadius / 2 + 50;
    CGFloat height = self.circelRadius / 2 - 50;
    CGFloat xPixel = self.bgImageView.left + (self.bgImageView.width - width)*0.5;//self.circelRadius / 4;
    CGFloat yPixel = self.circelRadius / 4;
    CGRect labelFrame = CGRectMake(xPixel, yPixel, width, height);
    _showLable = [[UILabel alloc] initWithFrame:labelFrame];
    _showLable.backgroundColor = [UIColor clearColor];
    _showLable.textColor = [UIColor greenColor];
    _showLable.textAlignment = NSTextAlignmentCenter;
    _showLable.font = [UIFont systemFontOfSize:100.f];
    _showLable.text = [NSString stringWithFormat:@"%ld",jumpCurrentNO];
    [self addSubview:_showLable];

    // 提示語
    _markedLabel = [[UILabel alloc] initWithFrame:CGRectMake(xPixel, CGRectGetMaxY(_showLable.frame), width, 30)];
    _markedLabel.backgroundColor = [UIColor clearColor];
    _markedLabel.textColor = [UIColor greenColor];
    _markedLabel.textAlignment = NSTextAlignmentCenter;
    _markedLabel.font = [UIFont systemFontOfSize:20.f];
    _markedLabel.text = @"營養良好";
    [self addSubview:_markedLabel];
}

#pragma mark - Animation

- (void)createAnimationWithStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle { // 光標動畫

    //啟動定時器
    [_fastTimer setFireDate:[NSDate distantPast]];
    // 設置動畫屬性
    CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    pathAnimation.calculationMode = kCAAnimationPaced;
    pathAnimation.fillMode = kCAFillModeForwards;
    pathAnimation.removedOnCompletion = NO;
    pathAnimation.duration = _percent * kTimerInterval;
    pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    pathAnimation.repeatCount = 1;

    // 設置動畫路徑
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddArc(path, NULL, self.width / 2, self.height / 2, (self.circelRadius - kMarkerRadius / 2) / 2, startAngle, endAngle, 0);
    pathAnimation.path = path;
    CGPathRelease(path);

    [self.markerImageView.layer addAnimation:pathAnimation forKey:@"moveMarker"];

}

#pragma mark - Setters / Getters


/**
 *  開始動畫  確定百分比
 *
 */
- (void)refreshJumpNOFromNO:(NSString *)startNO toNO:(NSString *)toNO {

    beginNO = 0;//[startNO integerValue];
    jumpCurrentNO = 0;//[startNO integerValue];
    endNO = [toNO integerValue];
    _percent = endNO * 100 / MaxNumber;

    NSInteger diffNum = endNO - beginNO;
    if (diffNum <= 0) {
        return;
    }
    if (diffNum < 100) {
        _intervalNum = 5;
    } else if (diffNum < 300) {
        _intervalNum = 15;
    } else if (diffNum <= MaxNumber) {
        _intervalNum = 10;
    }
    NSLog(@"數字間隔:%ld",_intervalNum);

    //數字
    [self setupJumpThings];

    // 設置角度
    NSInteger angle = 0;
    NSInteger num = [toNO floatValue] - [startNO floatValue];
    if (num < 200) {
        angle = self.startAngle + 220 * (num / 200.0) / 5.0;
    } else if (num < 350) {
        angle = self.startAngle + 220 / 5.0 + (3 / 5.0 * 220) * (num - 200) / 150.0;
    } else {
        angle = self.startAngle + 220 / 5.0 * 4 + (220 / 5.0) * (num - 350) / 250.0;
    }

    //光標
    [self createAnimationWithStartAngle:degreesToRadians(self.startAngle)
                               endAngle:degreesToRadians(angle)];
}

- (void)setBgImage:(UIImage *)bgImage {

    _bgImage = bgImage;
    self.bgImageView.image = bgImage;
}

- (UIImageView *)bgImageView {

    if (nil == _bgImageView) {
        _bgImageView = [[UIImageView alloc] init];
    }
    return _bgImageView;
}

#pragma mark - 躍動數字

- (void)setupJumpThings {

    animationTime = _percent * kTimerInterval;

    self.fastTimer = [NSTimer timerWithTimeInterval:kTimerInterval*kFastProportion
                                             target:self
                                           selector:@selector(fastTimerAction)
                                           userInfo:nil
                                            repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:_fastTimer forMode:NSRunLoopCommonModes];

    //時間間隔 = (總時間 - 快時間間隔*變化次數)/ 再次需要變化的次數
    //快時間
    NSInteger fastEndNO = endNO * kFastProportion;

    NSInteger fastJump = fastEndNO/_intervalNum;
    if (fastJump % _intervalNum) {
        fastJump++;
        fastEndNO += _intervalNum;
    }
    CGFloat fastTTime = fastJump*kTimerInterval*kFastProportion;

    //剩余應跳動次數
    NSInteger changNO = endNO - fastEndNO;
    NSInteger endJump = changNO / _intervalNum + changNO % _intervalNum;
    //慢時間間隔
    NSTimeInterval slowInterval = (animationTime - fastTTime) / endJump;

    self.slowTimer = [NSTimer timerWithTimeInterval:slowInterval
                                             target:self
                                           selector:@selector(slowTimerAction)
                                           userInfo:nil
                                            repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:_slowTimer forMode:NSRunLoopCommonModes];
    [_fastTimer setFireDate:[NSDate distantFuture]];
    [_slowTimer setFireDate:[NSDate distantFuture]];
}

#pragma mark 加速定時器觸發事件
- (void)fastTimerAction {
    if (jumpCurrentNO >= endNO) {
        [self.fastTimer invalidate];
        return;
    }
    if (jumpCurrentNO >= endNO * kFastProportion) {
        [self.fastTimer invalidate];
        [self.slowTimer setFireDate:[NSDate distantPast]];
        return;
    }
    [self commonTimerAction];
}

#pragma mark 減速定時器觸發事件
- (void)slowTimerAction {
    if (jumpCurrentNO >= endNO) {
        [self.slowTimer invalidate];
        return;
    }
    [self commonTimerAction];
}

#pragma mark 計時器共性事件 - lable賦值 背景顏色及提示語變化
- (void)commonTimerAction {

    if (jumpCurrentNO % 100 == 0 && jumpCurrentNO != 0) {
        NSInteger colorIndex = jumpCurrentNO / 100;
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.TimerBlock) {
                self.TimerBlock(colorIndex);
            }
        });
    }
    NSInteger changeValueBy = endNO - jumpCurrentNO;

    if (changeValueBy/10 < 1) {
        jumpCurrentNO++;
    } else {
//        NSInteger changeBy = changeValueBy / 10;
        jumpCurrentNO += _intervalNum;
    }

    _showLable.text = [NSString stringWithFormat:@"%ld",jumpCurrentNO];
    if (jumpCurrentNO < 350) {
        _markedLabel.text = @"營養太差";
    } else if (jumpCurrentNO <= 550) {
        _markedLabel.text = @"營養較差";
    } else if (jumpCurrentNO <= 600) {
        _markedLabel.text = @"營養中等";
    } else if (jumpCurrentNO <= 650) {
        _markedLabel.text = @"營養良好";
    } else if (jumpCurrentNO <= 700) {
        _markedLabel.text = @"營養優秀";
    } else if (jumpCurrentNO <= 950) {
        _markedLabel.text = @"營養較好";
    }
}

@end

在所需的當前控制器里展示:

//
//  ViewController.m
//  ZLDashboard
//
//  Created by qtx on 16/9/19.
//  Copyright ? 2016年 ZL. All rights reserved.
//

#import "ViewController.h"
#import "ZLDashboardView.h"
#import "ZLGradientView.h"
#import "UIView+Extensions.h"


#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)

#define MinNumber 350
#define MaxNumber 950


@interface ViewController ()

@property (nonatomic, strong) ZLDashboardView *dashboardView;

@property (nonatomic, strong) ZLGradientView * gradientView;

@property (nonatomic, strong) UIButton * clickBtn;

@property (nonatomic, strong) UISlider * slider;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //創建背景色
    [self setupGradientView];

    //創建儀表盤
    [self setupCircleView];

    //添加觸發動畫的點擊button
    [self addActionButton];

    //改變value
    [self addSlideChnageValue];

}

- (void)addActionButton {
    UIButton *stareButton = [UIButton buttonWithType:UIButtonTypeCustom];
    stareButton.frame = CGRectMake(10.f, self.dashboardView.bottom + 50.f, SCREEN_WIDTH - 20.f, 38.f);
    [stareButton addTarget:self action:@selector(onStareButtonClick:) forControlEvents:UIControlEventTouchUpInside];
    [stareButton setTitle:@"Start Animation" forState:UIControlStateNormal];
    [stareButton setBackgroundColor:[UIColor lightGrayColor]];
    stareButton.layer.masksToBounds = YES;
    stareButton.layer.cornerRadius = 4.f;
    [self.view addSubview:stareButton];

    _clickBtn = stareButton;
}

- (void)addSlideChnageValue {

    CGFloat width = 280;
    CGFloat height = 40;
    CGFloat xPixel = (SCREEN_WIDTH - width) * 0.5;
    CGFloat yPixel = CGRectGetMaxY(_clickBtn.frame) + 20;
    CGRect slideFrame = CGRectMake(xPixel, yPixel, width, height);

    UISlider *slider = [[UISlider alloc] initWithFrame:slideFrame];

    slider.minimumValue = MinNumber;
    slider.maximumValue = MaxNumber;

    slider.minimumTrackTintColor = [UIColor colorWithRed:0.000 green:1.000 blue:0.502 alpha:1.000];
    slider.maximumTrackTintColor = [UIColor colorWithWhite:0.800 alpha:1.000];
    /**
     *  注意這個屬性:如果你沒有設置滑塊的圖片,那個這個屬性將只會改變已劃過一段線條的顏色,不會改變滑塊的顏色,如果你設置了滑塊的圖片,又設置了這個屬性,那么滑塊的圖片將不顯示,滑塊的顏色會改變(IOS7)
     */
    [slider setThumbImage:[UIImage imageNamed:@""] forState:UIControlStateNormal];
    slider.thumbTintColor = [UIColor cyanColor];


    [slider setValue:0.5 animated:YES];

    [slider addTarget:self action:@selector(slideTap:)forControlEvents:UIControlEventValueChanged];

    [self.view addSubview:slider];

    _slider = slider;
}

- (void)slideTap:(UISlider *)sender {
    CGFloat value = sender.value;
    NSLog(@"%.f",value);
}

- (void)setupGradientView {
    self.gradientView = [[ZLGradientView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:self.gradientView];
}

- (void)setupCircleView {
    self.dashboardView = [[ZLDashboardView alloc] initWithFrame:CGRectMake(40.f, 70.f, SCREEN_WIDTH - 80.f, SCREEN_WIDTH - 80.f)];
    self.dashboardView.bgImage = [UIImage imageNamed:@"backgroundImage"];
    [self.view addSubview:self.dashboardView];
}

- (void)onStareButtonClick:(UIButton *)sender {

    if (sender.selected) {
        [self.gradientView removeFromSuperview];
        self.gradientView = nil;
        [self.dashboardView removeFromSuperview];
        self.dashboardView = nil;

        [self setupGradientView];
        [self setupCircleView];

        [self.view bringSubviewToFront:self.clickBtn];
        [self.view bringSubviewToFront:_slider];
    }
    sender.selected = YES;

    CGFloat value = _slider.value;

    NSString *startNO = [NSString stringWithFormat:@"%d", MinNumber];
    NSString *toNO = [NSString stringWithFormat:@"%.f",value];//@"693"; 950
    NSLog(@"endNO:%@",toNO);
    [self.dashboardView refreshJumpNOFromNO:startNO toNO:toNO];

    __block typeof(self)blockSelf = self;
    self.dashboardView.TimerBlock = ^(NSInteger index) {
        [blockSelf.gradientView setUpBackGroundColorWithColorArrayIndex:index];
    };
}

@end

 

 

來自:http://www.jianshu.com/p/9f80840175db

 

 本文由用戶 OPENKING 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!