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

IOS使用progssview仿滴滴打车圆形计时

程序员文章站 2022-03-23 13:14:16
实现类似在微信中使用的滴滴打车的progressview,实现效果如图 // // ccprogressview.h // hurricaneconsum...

实现类似在微信中使用的滴滴打车的progressview,实现效果如图

IOS使用progssview仿滴滴打车圆形计时

//
// ccprogressview.h
// hurricaneconsumer
//
// created by wangcong on 15-3-25.
// copyright (c) 2015年 wangcong. all rights reserved.
//
 
#import <uikit/uikit.h>
#import <quartzcore/quartzcore.h>
 
/**
 * 动画开始
 */
typedef void(^block_progress_start)();
 
/**
 * 动画正在进行
 * @param nstimeinterval
 */
typedef void(^block_progress_animing)(nstimeinterval);
 
/**
 * 动画结束
 */
typedef void(^block_progress_stop)();
 
@interface ccprogressview : uiview
{
  nstimeinterval _animationtime;
}
 
@property (nonatomic, strong) uilabel *centerlabel;    // 中心label
 
@property (nonatomic, copy) block_progress_start start;   // 动画开始回调
@property (nonatomic, copy) block_progress_animing animing; // 动画进行
@property (nonatomic, copy) block_progress_stop stop;    // 动画结束回调
 
- (void) setanimationtime:(nstimeinterval)animationtime;
 
- (void)startanimation;
 
- (void)stopanimation;
 
@end
 
 
//
// ccprogressview.m
// hurricaneconsumer
//
// created by wangcong on 15-3-25.
// copyright (c) 2015年 wangcong. all rights reserved.
//
 
#import "ccprogressview.h"
 
#define kprogressthumbwh 30
 
// 计时器间隔时长
#define kanimtimeinterval 0.1
 
/**
 * 圆圈layer上旋转的layer
 */
@interface ccprogressthumb : calayer
{
  nstimeinterval _animationtime;
}
 
@property (assign, nonatomic) double startangle;
@property (nonatomic, strong) uilabel *timelabel;      // 显示时间label
 
@end
 
@implementation ccprogressthumb
 
- (instancetype)init
{
  if ((self = [super init])) {
    [self setuplayer];
  }
  return self;
}
 
- (void)layoutsublayers
{
  _timelabel.frame = self.bounds;
   
  [_timelabel sizetofit];
  _timelabel.center = cgpointmake(cgrectgetmidx(self.bounds) - _timelabel.frame.origin.x,
                  cgrectgetmidy(self.bounds) - _timelabel.frame.origin.y);
}
 
- (void)setuplayer
{
  // 绘制圆
  uigraphicsbeginimagecontext(cgsizemake(kprogressthumbwh, kprogressthumbwh));
  cgcontextref ctx = uigraphicsgetcurrentcontext();
  cgcontextsetlinewidth(ctx, 1);
  cgcontextsetfillcolorwithcolor(ctx, [uicolor lightgraycolor].cgcolor);
  cgcontextsetstrokecolorwithcolor(ctx, [uicolor lightgraycolor].cgcolor);
  cgcontextaddellipseinrect(ctx, cgrectmake(1, 1, kprogressthumbwh - 2, kprogressthumbwh - 2));
  cgcontextdrawpath(ctx, kcgpathfillstroke);
  uiimage *circle = uigraphicsgetimagefromcurrentimagecontext();
  uigraphicsendimagecontext();
   
  uiimageview *circleview = [[uiimageview alloc] initwithimage:circle];
  circleview.frame = cgrectmake(0, 0, kprogressthumbwh, kprogressthumbwh);
  circleview.image = circle;
  [self addsublayer:circleview.layer];
   
  _timelabel = [[uilabel alloc] initwithframe:self.bounds];
  _timelabel.textcolor = [uicolor redcolor];
  _timelabel.font = [uifont systemfontofsize:10];
  _timelabel.textalignment = nstextalignmentcenter;
  _timelabel.text = @"00:00";
  [self addsublayer:_timelabel.layer];
   
  _startangle = - m_pi / 2;
}
 
- (void)setanimationtime:(nstimeinterval)animationtime
{
  _animationtime = animationtime;
}
 
- (double)calculatepercent:(nstimeinterval)fromtime totime:(nstimeinterval)totime
{
  double progress = 0.0f;
  if ((totime > 0) && (fromtime > 0)) {
    progress = fromtime / totime;
    if ((progress * 100) > 100) {
      progress = 1.0f;
    }
  }
  return progress;
}
 
- (void)startanimation
{
  cakeyframeanimation *pathanimation = [cakeyframeanimation animationwithkeypath:@"position"];
  pathanimation.calculationmode = kcaanimationpaced;
  pathanimation.fillmode = kcafillmodeforwards;
  pathanimation.removedoncompletion = yes;
  pathanimation.duration = kanimtimeinterval;
  pathanimation.repeatcount = 0;
  pathanimation.autoreverses = yes;
   
  cgmutablepathref arcpath = cgpathcreatemutable();
  cgpathaddpath(arcpath, null, [self bezierpathfromparentlayerarccenter]);
  pathanimation.path = arcpath;
  cgpathrelease(arcpath);
  [self addanimation:pathanimation forkey:@"position"];
}
 
/**
 * 根据父layer获取到一个移动路径
 * @return
 */
- (cgpathref)bezierpathfromparentlayerarccenter
{
  cgfloat centerx = cgrectgetwidth(self.superlayer.frame) / 2.0;
  cgfloat centery = cgrectgetheight(self.superlayer.frame) / 2.0;
  double tmpstartangle = _startangle;
  _startangle = _startangle + (2 * m_pi) * kanimtimeinterval / _animatetime;
  return [uibezierpath bezierpathwitharccenter:cgpointmake(centerx, centery)
                     radius:centerx
                   startangle:tmpstartangle
                    endangle:_startangle
                    clockwise:yes].cgpath;
}
 
- (void)stopanimation
{
  [self removeallanimations];
}
 
- (void)dealloc
{
  [[nsnotificationcenter defaultcenter] removeobserver:self];
}
 
@end
 
/**
 * 圆圈layer
 */
@interface ccprogress : cashapelayer
{
  nstimeinterval _animationtime;
}
 
@property (assign, nonatomic) double initialprogress;
@property (nonatomic) nstimeinterval elapsedtime;                   //已使用时间
@property (assign, nonatomic) double percent;
@property (nonatomic, strong) uicolor *circlecolor;
@property (nonatomic, strong) cashapelayer *progress;
@property (nonatomic, strong) ccprogressthumb *thumb;
@property (nonatomic, assign) cgrect frame;
 
@end
 
@implementation ccprogress
 
- (instancetype) init
{
  if ((self = [super init])) {
    [self setuplayer];
  }
  return self;
}
 
- (void)layoutsublayers
{
  self.path = [self bezierpathwitharccenter];
  self.progress.path = self.path;
   
  self.thumb.frame = cgrectmake((320 - kprogressthumbwh) / 2.0f, 180, kprogressthumbwh, kprogressthumbwh);
  [super layoutsublayers];
}
 
- (void)setuplayer
{
  // 绘制圆
  self.path = [self bezierpathwitharccenter];
  self.fillcolor = [uicolor clearcolor].cgcolor;
  self.strokecolor = [uicolor colorwithred:0.86f green:0.86f blue:0.86f alpha:0.4f].cgcolor;
  self.linewidth = 2;
   
  // 添加可以变动的滚动条
  self.progress = [cashapelayer layer];
  self.progress.path = self.path;
  self.progress.fillcolor = [uicolor clearcolor].cgcolor;
  self.progress.strokecolor = [uicolor whitecolor].cgcolor;
  self.progress.linewidth = 4;
  self.progress.linecap = kcalinecapsquare;
  self.progress.linejoin = kcalinecapsquare;
  [self addsublayer:self.progress];
   
  // 添加可以旋转的thumblayer
  self.thumb = [[ccprogressthumb alloc] init];
  [self addsublayer:self.thumb];
}
 
/**
 * 得到bezier曲线路劲
 * @return
 */
- (cgpathref)bezierpathwitharccenter
{
  cgfloat centerx = cgrectgetwidth(self.frame) / 2.0;
  cgfloat centery = cgrectgetheight(self.frame) / 2.0;
  return [uibezierpath bezierpathwitharccenter:cgpointmake(centerx, centery)
                     radius:centerx
                   startangle:(- m_pi / 2)
                    endangle:(3 * m_pi / 2)
                    clockwise:yes].cgpath;
}
 
- (void)setcirclecolor:(uicolor *)circlecolor
{
  self.progress.strokecolor = circlecolor.cgcolor;
}
 
- (void)setanimtiontime:(nstimeinterval)animtiontime
{
  _animationtime = animtiontime;
  [self.thumb setanimationtime:animtiontime];
}
 
- (void)setelapsedtime:(nstimeinterval)elapsedtime
{
  _initialprogress = [self calculatepercent:_elapsedtime totime:_animationtime];
  _elapsedtime = elapsedtime;
   
  self.progress.strokeend = self.percent;
  [self startanimation];
}
 
- (double)percent
{
  _percent = [self calculatepercent:_elapsedtime totime:_animationtime];
  return _percent;
}
 
- (double)calculatepercent:(nstimeinterval)fromtime totime:(nstimeinterval)totime
{
  double progress = 0.0f;
  if ((totime > 0) && (fromtime > 0)) {
    progress = fromtime / totime;
    if ((progress * 100) > 100) {
      progress = 1.0f;
    }
  }
  return progress;
}
 
- (void)startanimation
{
  cabasicanimation *pathanimation = [cabasicanimation animationwithkeypath:@"strokeend"];
  pathanimation.duration = kanimtimeinterval;
  pathanimation.fromvalue = @(self.initialprogress);
  pathanimation.tovalue = @(self.percent);
  pathanimation.removedoncompletion = yes;
  [self.progress addanimation:pathanimation forkey:nil];
   
  [self.thumb startanimation];
  self.thumb.timelabel.text = [self stringfromtimeinterval:_elapsedtime shortime:yes];
}
 
- (void)stopanimation
{
  _elapsedtime = 0;
  self.progress.strokeend = 0.0;
  [self removeallanimations];
  [self.thumb stopanimation];
}
 
/**
 * 时间格式转换
 * @param interval nstimeinterval
 * @param shorttime bool
 * @return
 */
- (nsstring *)stringfromtimeinterval:(nstimeinterval)interval shortime:(bool)shorttime
{
  nsinteger ti = (nsinteger)interval;
  nsinteger seconds = ti % 60;
  nsinteger minutes = (ti / 60) % 60;
  nsinteger hours = (ti / 3600);
  if (shorttime) {
    return [nsstring stringwithformat:@"%02ld:%02ld", (long)hours, (long)seconds];
  } else {
    return [nsstring stringwithformat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
  }
}
 
@end
 
@interface ccprogressview ()
 
@property (nonatomic, strong) ccprogress *progresslayer;
@property (nonatomic, strong) nstimer *timer;
 
@end
 
@implementation ccprogressview
 
- (instancetype)init
{
  if ((self = [super init])) {
    [self setupview];
  }
  return self;
}
 
- (instancetype)initwithframe:(cgrect)frame
{
  if ((self = [super initwithframe:frame])) {
    [self setupview];
  }
  return self;
}
 
- (void)layoutsubviews
{
  [super layoutsubviews];
  self.progresslayer.frame = self.bounds;
   
  [self.centerlabel sizetofit];
  self.centerlabel.center = cgpointmake(self.center.x - self.frame.origin.x, self.center.y- self.frame.origin.y);
}
 
- (void)setupview
{
  self.backgroundcolor = [uicolor clearcolor];
  self.clipstobounds = false;
   
  self.progresslayer = [[ccprogress alloc] init];
  self.progresslayer.frame = self.bounds;
  [self.layer addsublayer:self.progresslayer];
   
  _centerlabel = [[uilabel alloc] initwithframe:self.bounds];
  _centerlabel.font = [uifont systemfontofsize:18];
  _centerlabel.textalignment = nstextalignmentcenter;
  _centerlabel.textcolor = [uicolor whitecolor];
  _centerlabel.text = @"已推送至 3 家";
  [self.layer addsublayer:_centerlabel.layer];
}
 
- (void)setanimationtime:(nstimeinterval)animationtime
{
  _animationtime = animationtime;
  [self.progresslayer setanimtiontime:animationtime];
}
 
- (void)startanimation
{
  if (!_timer) {
    _timer = [nstimer timerwithtimeinterval:kanimtimeinterval target:self selector:@selector(dotimerschedule) userinfo:nil repeats:yes];
    [[nsrunloop currentrunloop] addtimer:_timer formode:nsrunloopcommonmodes];
  }
  self.progresslayer.elapsedtime = 0;
  if (_start) _start();
}
 
- (void)dotimerschedule
{
  self.progresslayer.elapsedtime = self.progresslayer.elapsedtime + kanimtimeinterval;;
  if (_animing) _animing(self.progresslayer.elapsedtime);
   
  if (self.progresslayer.elapsedtime >= _animationtime) {
    [self stopanimation];
  }
}
 
- (void)stopanimation
{
  if (_stop) _stop();
  if (_timer) {
    [_timer invalidate];
    _timer = nil;
  }
  [_progresslayer stopanimation];
}
 
@end
 
使用实例
_progressview = [[ccprogressview alloc] initwithframe:cgrectmake((app_width - 240) / 2.0f, (app_height - 240) / 2.0f, 240, 240)];
  [_progressview setanimationtime:60];
  _progressview.start = ^() {
    nslog(@"开始");
  };
  _progressview.animing = ^ (nstimeinterval currenttime) {
    nslog(@"进行中");
  };
  __block id weakself = self;
  _progressview.stop = ^ () {
    nslog(@"结束");
    [weakself dismiss];
  };
  [self addsubview:_progressview];
   
  [_progressview startanimation];

以上所述就是本文的全部内容了,希望大家能够喜欢