当前位置: 移动技术网 > 移动技术>移动开发>IOS > IOS使用progssview仿滴滴打车圆形计时

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

2019年07月24日  | 移动技术网移动技术  | 我要评论
实现类似在微信中使用的滴滴打车的progressview,实现效果如图 // // ccprogressview.h // hurricaneconsum

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

//
// 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];

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网