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

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

程序员文章站 2024-02-08 19:53:28
前言 大家应该都知道在app开发中,当展示限时优惠的某些商品时,往往会加一个倒计时,提示用户该商品限时优惠所剩的时间,。那对于开发者来说,这就需要我们去实现的是一个倒计时...

前言

大家应该都知道在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上下载

二:本地下载

总结

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