热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

iOS中让多个cell上都出现倒计时的分析与实现

这篇文章主要给大家介绍了在iOS中每个cell上都出现倒计时的分析与实现,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。

前言

以前就有人问过这样一个问题:如果一个tableView的很多或者所有cell上都显示一个倒计时,该怎么实现? 今天自己恰好也遇到了这样的需求:很多产品,每个都有一个时限,在时限内才可以申购,过了申购功能就会关闭.简单描述就是,每个cell上有个倒计时,时间结束与否,点击cell响应的事件是不一样的.那么怎么实现呢?下面谈谈自己的思考过程.

1.Cell内部加一个定时器

既然每个cell都有一个倒计时,时间还可能不一样.根据"高内聚,低耦合"的思想,我首先想着直接让cell自己来实现倒计时功能:每个cell添加一个NSTimer,没隔1秒,让其显示的时间减少一秒.

- (void)timeChange {
 self.totalSeconds --;
 if (self.totalSeconds <0) {
   self.timerLabel.text = @"倒计时结束";
  return;
 }
 self.timerLabel.text = [self timeChangeWithSeconds:self.totalSeconds];
}
- (void)setDataDict:(NSDictionary *)dataDict {
 _dataDict = dataDict;
 NSString *totalTime = dataDict[@"totalTime"];
 self.totalSecOnds= totalTime.integerValue;
 self.timerLabel.text = [self timeChangeWithSeconds:self.totalSeconds];
 if (!_timer) {
  _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
  [[NSRunLoop currentRunLoop] addTimer:_timer forMode:UITrackingRunLoopMode];
 }
}
- (NSString*)timeChangeWithSeconds:(NSInteger)seconds {
 NSInteger temp1 = seconds/60;
 NSInteger temp2 = temp1/ 60;
 NSInteger d = temp2 / 24;
 NSInteger h = temp2 % 24;
 NSInteger m = temp1 % 60;
 NSInteger s = seconds %60;
 NSString * hour = h<9 &#63; [NSString stringWithFormat:@"0%ld",(long)h] :[NSString stringWithFormat:@"%ld",(long)h];
 NSString *day = d <9 &#63; [NSString stringWithFormat:@"0%ld",(long)d] : [NSString stringWithFormat:@"%ld",(long)d];
 NSString *minite = m <9 &#63; [NSString stringWithFormat:@"0%ld",(long)m] : [NSString stringWithFormat:@"%ld",(long)m];
 NSString *secOnd= s <9 &#63; [NSString stringWithFormat:@"0%ld",(long)s] : [NSString stringWithFormat:@"%ld",(long)s];
 return [NSString stringWithFormat:@"%@天:%@时:%@分:%@秒",day,hour,minite,second];
}

乍看,好像一切都OK,但是当我们拖动cell时,会发现一旦cell移除屏幕,再拖回来的时候,又会重头倒计时.当然,这和我在setDataDict:方法中的赋值方式有关,可以通过totalSeconds这个属性,保存当前剩余的时间,下一次再进来的时候,去取保存好的值.

- (void)setDataDict:(NSDictionary *)dataDict {
 _dataDict = dataDict;
  if (self.totalSeconds !=0) {
   self.timerLabel.text = [self timeChangeWithSeconds:self.totalSeconds];
 }else {
  NSString *totalTime = dataDict[@"totalTime"];
  self.totalSecOnds= totalTime.integerValue;
  self.timerLabel.text = [self timeChangeWithSeconds:self.totalSeconds];
 }
  if (!_timer) {
  _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
  [[NSRunLoop currentRunLoop] addTimer:_timer forMode:UITrackingRunLoopMode];
 }
}

这样做,会发现当cell移除屏幕,再移回来的时候,不再是从头倒计时,但是多拖动几次又会发现新的问题:显示错乱,某个cell出现在了不该出现的位置.

仔细分析不难发现,cell的复用机制是引起上述现象的"罪魁祸首",要解决这个问题,可以让cell不复用,比方说,可以给每个cell绑定不同的标识,达到不复用的目的,看到这里,如果你也是这么想的,那么最好打住,因为为了达到这个目的,而让cell不复用,以牺牲内存占用为代价,无疑是饮鸩止渴,丢了西瓜,捡个芝麻.

值得的注意的是,如果在cell中实现,每个cell都添加一个定时器,这也是一笔可观的开销.

2. 在tableView的parentView中实现

既然在cell中实现遇到的坑比较多,那么又想着在外面做.这样有一个明显的好处,就是只需要一个定时器.每次触发,让每个cell上显示的时间递减.由于tableView的显示,取决于传入的数据,只要我在传入数据之前把需要传的数据处理好,这样就不会因为cell的复用机制而带来显示错乱的问题.运行代码,发现问题圆满解决!

/**定时器触发*/
- (void)timeChange {
 NSMutableArray *tempArrM = [NSMutableArray array];
 for (NSDictionary *dict in self.dataArr) {
  NSString *totalTime = dict[@"totalTime"];
  if ([totalTime isEqualToString:@"0"]) {
    totalTime = @"0";
  }else {
   totalTime = [NSString stringWithFormat:@"%ld",totalTime.integerValue -1];
  }
  [tempArrM addObject:@{@"totalTime":totalTime}];
 }
 self.dataArr = tempArrM;
 [self.pageTableView reloadData];
}

3. 值得注意的几个地方

当我们拖动cell时,如果发现定时器不工作,可以用如下方式解决.

 _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
   [[NSRunLoop currentRunLoop] addTimer:_timer forMode:UITrackingRunLoopMode];

关于数据的传入:

  • 直接提供产品到目前为止还剩多少时间.每个产品对应一个总的时间,用于倒计时.那么,后台给我提供时间时就可以把每个产品对应的总时间返给我们.但是,这样就要求后台自己实时去计算每个产品在我们请求数据时还剩多少时间.
  • 后台把每种产品的截止时间和当前的系统时间返给我们.系统时间,我们可用于矫正自己的系统时间(APP显示的时间是可以人为修改的,并且不通设备之间,iOS与Android之间的时间有可能存在差异,为了统一所以需要矫正),通过矫正好的时间和截止时间,我们就能知道,该产品还剩多少时间.

虽然,我这边自己用的第一种方式写的Demo,但是,相比之下,我更加倾向于第二种数据的传递方式,准确性高,也能为后端同事剩些事.

总结

由于这只是一个最初的Demo,也只是一些个人的初步看法,难免有些疏漏,如有纰漏,还望指正.

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


推荐阅读
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
author-avatar
政委锤炼_394_774
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有