欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS仿支付宝芝麻信用分数仪表盘动画效果

程序员文章站 2024-02-12 09:27:46
先看看效果图: 仪表盘动画效果.jpg 1.圆环上绿点的旋转 2.分数值及提示语的变化 3.背景色的变化 直接上主要代码: 1.自定义zldashboard...

先看看效果图:

iOS仿支付宝芝麻信用分数仪表盘动画效果

仪表盘动画效果.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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。