iOS仿支付宝芝麻信用分数仪表盘动画效果
程序员文章站
2023-12-16 08:13:16
先看看效果图:
仪表盘动画效果.jpg
1.圆环上绿点的旋转
2.分数值及提示语的变化
3.背景色的变化
直接上主要代码:
1.自定义zldashboard...
先看看效果图:
仪表盘动画效果.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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。