先看看效果圖:
儀表盤動畫效果.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
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。