当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS实现毫秒倒计时的方法详解

iOS实现毫秒倒计时的方法详解

2019年07月24日  | 移动技术网IT编程  | 我要评论

金怡云,热血英豪傀儡师,张杰几岁

前言

大家应该都知道在app开发中,当展示限时优惠的某些商品时,往往会加一个倒计时,提示用户该商品限时优惠所剩的时间,。那对于开发者来说,这就需要我们去实现的是一个倒计时的功能,这个倒计时根据具体需求,可以以天、小时、分、秒、毫秒作单位。

今天呢,主要说说毫秒计时器。我们知道秒和毫秒之间的进制是1000,也就是说1秒=1000毫秒,那我们做毫秒倒计时器的时候是设置一个时间间隔为1毫秒的计时器,逐一减少毫秒数。但是这样的话太耗时了,所以很多的毫秒计时器中的毫秒数只是0-9之间的数字,这就意味着,这个毫秒计时器的时间间隔是100毫秒,这样相比起1毫秒为间隔的计时器,其消耗就少了很多,同时也达到毫秒计时的效果。

那对于整个毫秒倒计时的实现思路就是:得到未来某个日期的时间戳和当前日期的时间戳,计算这两者之间的时间差,然后设置一个时间间隔为100毫秒的计时器,每隔100毫秒,更新一下倒计时器上相应的数值。

实现方法

自定义一个uiview,将倒计时封装起来。

一、在mseccountdownview.h中增加时间戳和计时器这两属性

@interface mseccountdownview : uiview

@property(nonatomic, assign)double timeinterval;//未来某个日期的时间戳
@property(nonatomic, strong)nstimer *timer ; //定时器

@end

二、在mseccountdownview.m实现相关ui及倒计时方法

@interface mseccountdownview (){
uiview *countdownbackview;
cgfloat _passtime;
}
@property(nonatomic, strong)uilabel *tiplabel;
@property(nonatomic, strong)uilabel *hourslabel;
@property(nonatomic, strong)uilabel *minuteslabel;
@property(nonatomic, strong)uilabel *secondslabel;
@property(nonatomic, strong)uilabel *millionsecondslabel;
@property(nonatomic, strong)uilabel *label1;
@property(nonatomic, strong)uilabel *label2;
@property(nonatomic, strong)uilabel *label3;
@property(nonatomic, strong)uilabel *label4;
@end

创建相关ui

- (instancetype)initwithframe:(cgrect)frame
{
 self = [super initwithframe:frame];

 if (self) {

  countdownbackview=[[uiview alloc] initwithframe:cgrectmake(0, 0, self.frame.size.width, self.frame.size.height)];
  [self addsubview:countdownbackview];
  _tiplabel=[[uilabel alloc] init];
  _tiplabel.frame = cgrectmake(0, 0, 40, countdownbackview.frame.size.height);
  [countdownbackview addsubview:_tiplabel];

  _tiplabel.font = [uifont systemfontofsize:12];


  //小时
  _hourslabel=[[uilabel alloc] initwithframe:cgrectmake(_tiplabel.frame.origin.x+_tiplabel.frame.size.width, 0, 35, countdownbackview.frame.size.height)];
  [countdownbackview addsubview:_hourslabel];
  _hourslabel.font = [uifont systemfontofsize:11];

  _label1=[[uilabel alloc] initwithframe:cgrectmake(_hourslabel.frame.origin.x+_hourslabel.frame.size.width, _hourslabel.frame.origin.y, 8, countdownbackview.frame.size.height)];
  [countdownbackview addsubview:_label1];

  //分钟
  _minuteslabel=[[uilabel alloc] initwithframe:cgrectmake(_label1.frame.origin.x+_label1.frame.size.width, _hourslabel.frame.origin.y, 20, countdownbackview.frame.size.height)];
  [countdownbackview addsubview:_minuteslabel];
  _minuteslabel.font = [uifont systemfontofsize:11];

  _label2=[[uilabel alloc] initwithframe:cgrectmake(_minuteslabel.frame.origin.x+_minuteslabel.frame.size.width, _hourslabel.frame.origin.y, 8, countdownbackview.frame.size.height)];
  [countdownbackview addsubview:_label2];

  //秒
  _secondslabel=[[uilabel alloc] initwithframe:cgrectmake(_label2.frame.origin.x+_label2.frame.size.width, _hourslabel.frame.origin.y, 20 , countdownbackview.frame.size.height)];
  [countdownbackview addsubview:_secondslabel];


  _secondslabel.font = [uifont systemfontofsize:11];

  _label3=[[uilabel alloc] initwithframe:cgrectmake(_secondslabel.frame.origin.x+_secondslabel.frame.size.width, _hourslabel.frame.origin.y, 8 , countdownbackview.frame.size.height)];
  [countdownbackview addsubview:_label3];


  _millionsecondslabel=[[uilabel alloc] initwithframe:cgrectmake(_label3.frame.origin.x+_label3.frame.size.width, _hourslabel.frame.origin.y, 20, countdownbackview.frame.size.height)];
  [countdownbackview addsubview:_millionsecondslabel];


   //毫秒

  _millionsecondslabel.font = [uifont systemfontofsize:11];

  _label1.textalignment=1;
  _label2.textalignment=1;
  _label3.textalignment = 1;
  _hourslabel.textalignment=1;
  _minuteslabel.textalignment=1;
  _secondslabel.textalignment=1;
  _millionsecondslabel.textalignment=1;


  _passtime=0.0;
 }


 return self;
}

生成一个计时器

//得到未来某个日期的时间戳,与当前时间戳相比,得到两者的时间差,生成定时器
- (void)settimeinterval:(double)timeinterval
{

 _timeinterval = timeinterval ;

 nsdateformatter *dataformatter = [[nsdateformatter alloc] init];
 dataformatter.dateformat = @"mm/dd/yyyy hh:mm:ss.sss";

 //获取当前系统的时间,并用相应的格式转换
 [dataformatter stringfromdate:[nsdate date]];
 nsstring *currentdaystr = [dataformatter stringfromdate:[nsdate date]];
 nsdate *currentdate = [dataformatter datefromstring:currentdaystr];

 //优惠结束的时间,也用相同的格式去转换
 nsdate *date = [nsdate datewithtimeintervalsince1970:timeinterval/1000.0];
 nsstring *deadlinestr = [dataformatter stringfromdate:date];
 nsdate *deadlinedate = [dataformatter datefromstring:deadlinestr];

 _timeinterval=[deadlinedate timeintervalsincedate:currentdate]*1000;

 if (_timeinterval!=0)
 {

  //时间间隔是100毫秒,也就是0.1秒
  _timer = [nstimer scheduledtimerwithtimeinterval:0.1f target:self selector:@selector(timeraction) userinfo:nil repeats:yes];

  [[nsrunloop currentrunloop] addtimer:_timer formode:uitrackingrunloopmode];
 }else{
  [countdownbackview removefromsuperview];

 }

}

实现每隔100毫秒执行的方法,更新倒计时器上面相应的数值

// 每间隔100毫秒定时器触发执行该方法
- (void)timeraction
{

 [self gettimefromtimeinterval:_timeinterval] ;


 // 当时间间隔为0时干掉定时器
 if (_timeinterval-_passtime == 0)
 {
  [_timer invalidate] ;
  _timer = nil ;
 }
}

// 通过时间间隔计算具体时间(小时,分,秒,毫秒)
- (void)gettimefromtimeinterval : (double)timeinterval
{

 //1s=1000毫秒
 _passtime += 100.f;//毫秒数从0-9,所以每次过去100毫秒
 _tiplabel.text=@"还剩:";

 _label3.text=@".";
 _label2.text=@":";
 _label1.text=@":";

 //小时数
 nsstring *hours = [nsstring stringwithformat:@"%ld", (nsinteger)((timeinterval-_passtime)/1000/60/60)];
 //分钟数
 nsstring *minute = [nsstring stringwithformat:@"%ld", (nsinteger)((timeinterval-_passtime)/1000/60)%60];
 //秒数
 nsstring *second = [nsstring stringwithformat:@"%ld", ((nsinteger)(timeinterval-_passtime))/1000%60];
 //毫秒数
 cgfloat sss = ((nsinteger)((timeinterval - _passtime)))%1000/100;


 nsstring *ss = [nsstring stringwithformat:@"%.lf", sss];

 if (minute.integervalue < 10) {
  minute = [nsstring stringwithformat:@"0%@", minute];
 }


 self.hourslabel.text = [nsstring stringwithformat:@"%@",hours];
 self.minuteslabel.text = [nsstring stringwithformat:@"%@",minute];
 self.secondslabel.text = [nsstring stringwithformat:@"%@",second];
 self.millionsecondslabel.text = [nsstring stringwithformat:@"%@",ss];

 if (timeinterval - _passtime <= 0) {
  [countdownbackview removefromsuperview];
  [self removefromsuperview];
 }

}

三、在viewcontroller.m给倒计时器赋值,实现自己想要的倒计时

- (void)viewdidload {
 [super viewdidload];

 msecview=[[mseccountdownview alloc] initwithframe:cgrectmake(50, 100, self.view.frame.size.width-100, 16)];
 [self.view addsubview:msecview];

 nsdateformatter *formatter = [[nsdateformatter alloc] init];

 [formatter setdatestyle:nsdateformattermediumstyle];

 [formatter settimestyle:nsdateformattershortstyle];

 [formatter setdateformat:@"yyyy-mm-dd hh:mm:ss.sss"];


 nsdate* date = [formatter datefromstring:@"2017-04-11 15:10:00.000"];
 //将日期转换成时间戳
 nsinteger timesp = [[nsnumber numberwithdouble:[date timeintervalsince1970]] integervalue]*1000;

 msecview.timeinterval=timesp;

}

这样就实现倒计时的功能了。但是使用倒计时还需要注意一点,当离开该页面的时候,记得把定时器暂停,等回到该页面的时候再启动倒计时。

这个可以通过以下两方法实现。

-(void)viewwillappear:(bool)animated{

// 页面出现时,开启计时器 
 [msecview.timer setfiredate:[nsdate distantpast]];

}
-(void)viewwilldisappear:(bool)animated{
// 页面消失时,暂停提示器
 [msecview.timer setfiredate:[nsdate distantfuture]];
}

如有需要,可通过下面两种方法下载demo

一:github上下载

二:

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网