IOS使用progssview仿滴滴打车圆形计时
程序员文章站
2022-03-23 13:14:16
实现类似在微信中使用的滴滴打车的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];
以上所述就是本文的全部内容了,希望大家能够喜欢