collectionViewcell 写的活动促销倒计时
问题描述 :###
在屏幕滚动的时候,倒计时NSTimer 停止,滚动停止后,倒计时继续,这样就造成了时间差。
解决方案 :###
<p>先贴代码:</p>
#import <UIKit/UIKit.h>
#import "TimeCutView.h"
#import "ShopModel.h"
@interface ShopCell : UICollectionViewCell
//倒计时背景
@property (nonatomic,strong)UIImageView *timeBak;
//倒计时view
@property (nonatomic,strong) TimeCutView *countDown;
@end
@implementation ShopCell
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
_countDown= [TimeCutView countDown];
_timeBak = [[UIImageView alloc]initWithFrame:CGRectMake(0, _specialImg.frame.size.height-30, _specialImg.frame.size.width, 30)];
_timeBak.image = [UIImage imageNamed:@"daojishibg"];
UILabel *timeCutLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 0, 85, 30)];
timeCutLabel.text = @"距结束还有:";
timeCutLabel.textColor = [UIColor whiteColor];
timeCutLabel.font = [UIFont systemFontOfSize:13];
_countDown = [[TimeCutView alloc]init];
_countDown.frame = CGRectMake(75, 0, 100, 30);
[self addSubview:timeCutLabel];
[self addSubview:_countDown];
[self addSubview:_timeBak];
}
return self;
}
@end
#import <UIKit/UIKit.h>
typedef void(^TimerStopBlock)();
@interface TimeCutView : UIView
// 时间戳
@property (nonatomic,assign)NSInteger timestamp;
// 背景
@property (nonatomic,copy)NSString *backgroundImageName;
// 时间停止后回调
@property (nonatomic,copy)TimerStopBlock timerStopBlock;
@property (nonatomic,strong) UILabel *separateLabel;
/**
* 创建单例对象
*/
+ (instancetype)shareCountDown;// 工程中使用的倒计时是唯一的
/**
* 创建非单例对象
*/
+ (instancetype)countDown; // 工程中倒计时不是唯一的
@end
#import "TimeCutView.h"
// label数量
#define labelCount 3
#define separateLabelCount 2
#define padding 6
@interface TimeCutView (){
// 定时器
NSTimer *timer;
}
@property (nonatomic,strong)NSMutableArray *timeLabelArrM;
@property (nonatomic,strong)NSMutableArray *separateLabelArrM;
// day
@property (nonatomic,strong)UILabel *dayLabel;
// hour
@property (nonatomic,strong)UILabel *hourLabel;
// minues
@property (nonatomic,strong)UILabel *minuesLabel;
// seconds
@property (nonatomic,strong)UILabel *secondsLabel;
@end
@implementation TimeCutView
// 创建单例
+ (instancetype)shareCountDown{
static id instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[TimeCutView alloc] init];
});
return instance;
}
+ (instancetype)countDown{
return [[self alloc] init];
}
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
[self addSubview:self.dayLabel];
[self addSubview:self.hourLabel];
[self addSubview:self.minuesLabel];
[self addSubview:self.secondsLabel];
for (NSInteger index = 0; index < separateLabelCount; index ++) {
_separateLabel = [[UILabel alloc] init];
_separateLabel.text = @":";
_separateLabel.textAlignment = NSTextAlignmentCenter;
_separateLabel.textColor = [UIColor whiteColor];
_separateLabel.font = [UIFont systemFontOfSize:13];
[self addSubview:_separateLabel];
[self.separateLabelArrM addObject:_separateLabel];
}
}
return self;
}
- (void)setBackgroundImageName:(NSString *)backgroundImageName{
}
// 拿到外界传来的时间戳
- (void)setTimestamp:(NSInteger)timestamp{
_timestamp = timestamp;
if (_timestamp != 0) {
timer =[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timer:) userInfo:nil repeats:YES];
//##########################解决滑动时计时器停止###########################
// UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保
// 证界面滑动时不受其他 Mode 影响(操作 UI 界面的情况下运行)
// NSRunLoopCommonModes :这是一个占位用的 Mode,不是一种真正的 Mode
// (RunLoop无法启动该模式,设置这种模式下,默认和操作 UI
// 界面时线程都可以运行,但无法改变 RunLoop 同时只能在一种
// 模式下运行的本质)
// NSDefaultRunLoopMode : App 的默认 Mode,通常主线程是在这个 Mode
// 下运行(默认情况下运行)
//##########################解决滑动时计时器停止###########################
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
}
-(void)timer:(NSTimer*)timerr{
_timestamp--;
[self getDetailTimeWithTimestamp:_timestamp];
if (_timestamp == 0) {
[timer invalidate];
timer = nil;
// 执行block回调
self.timerStopBlock();
}
}
- (void)getDetailTimeWithTimestamp:(NSInteger)timestamp{
NSInteger ms = timestamp;
NSInteger ss = 1;
NSInteger mi = ss * 60;
NSInteger hh = mi * 60;
NSInteger dd = hh * 24;
// 剩余的
NSInteger day = ms / dd;// 天
NSInteger hour = (ms - day * dd) / hh;// 时
NSInteger minute = (ms - day * dd - hour * hh) / mi;// 分
NSInteger second = (ms - day * dd - hour * hh - minute * mi) / ss;// 秒
// NSLog(@"%zd日:%zd时:%zd分:%zd秒",day,hour,minute,second);
if (day == 0) {
// 获得view的宽、高
CGFloat viewW = self.frame.size.width;
CGFloat viewH = self.frame.size.height;
// 单个label的宽高
CGFloat labelW = viewW / labelCount;
CGFloat labelH = viewH;
self.dayLabel.text = @"";
[self.hourLabel setFrame:CGRectMake(0, 0, labelW, labelH)];
[self.minuesLabel setFrame:CGRectMake(labelW, 0, labelW, labelH)];
[self.secondsLabel setFrame:CGRectMake(2 * labelW , 0, labelW, labelH)];
for (NSInteger index = 0; index < self.separateLabelArrM.count ; index ++) {
_separateLabel = self.separateLabelArrM[index];
[_separateLabel setFrame: CGRectMake((labelW - 1) * (index + 1), 0, 5, labelH)];
}
self.hourLabel.text = [NSString stringWithFormat:@"%zd时",hour];
self.minuesLabel.text = [NSString stringWithFormat:@"%zd分",minute];
self.secondsLabel.text = [NSString stringWithFormat:@"%zd秒",second];
}else{
self.dayLabel.text = [NSString stringWithFormat:@"%zd天",day];
self.hourLabel.text = [NSString stringWithFormat:@"%zd时",hour];
self.minuesLabel.text = [NSString stringWithFormat:@"%zd分",minute];
self.secondsLabel.text = [NSString stringWithFormat:@"%zd秒",second];
}
}
- (void)layoutSubviews{
[super layoutSubviews];
// 获得view的宽、高
CGFloat viewW = self.frame.size.width;
CGFloat viewH = self.frame.size.height;
// 单个label的宽高
CGFloat labelW = viewW / labelCount;
CGFloat labelH = viewH;
self.dayLabel.frame = CGRectMake(0, 0, labelW, labelH);
self.hourLabel.frame = CGRectMake(labelW, 0, labelW, labelH);
self.minuesLabel.frame = CGRectMake(2 * labelW , 0, labelW, labelH);
self.secondsLabel.frame = CGRectMake(3 * labelW, 0, labelW, labelH);
for (NSInteger index = 0; index < self.separateLabelArrM.count ; index ++) {
_separateLabel = self.separateLabelArrM[index];
_separateLabel.frame = CGRectMake((labelW - 1) * (index + 2), 0, 5, labelH);
}
}
#pragma mark - setter & getter
- (NSMutableArray *)timeLabelArrM{
if (_timeLabelArrM == nil) {
_timeLabelArrM = [[NSMutableArray alloc] init];
}
return _timeLabelArrM;
}
- (NSMutableArray *)separateLabelArrM{
if (_separateLabelArrM == nil) {
_separateLabelArrM = [[NSMutableArray alloc] init];
}
return _separateLabelArrM;
}
- (UILabel *)dayLabel{
if (_dayLabel == nil) {
_dayLabel = [[UILabel alloc] init];
_dayLabel.textAlignment = NSTextAlignmentCenter;
_dayLabel.textColor = [UIColor whiteColor];
_dayLabel.font = [UIFont systemFontOfSize:13];
}
return _dayLabel;
}
- (UILabel *)hourLabel{
if (_hourLabel == nil) {
_hourLabel = [[UILabel alloc] init];
_hourLabel.textAlignment = NSTextAlignmentCenter;
_hourLabel.textColor = [UIColor whiteColor];
_hourLabel.font = [UIFont systemFontOfSize:13];
}
return _hourLabel;
}
- (UILabel *)minuesLabel{
if (_minuesLabel == nil) {
_minuesLabel = [[UILabel alloc] init];
_minuesLabel.textAlignment = NSTextAlignmentCenter;
_minuesLabel.textColor = [UIColor whiteColor];
_minuesLabel.font = [UIFont systemFontOfSize:13];
}
return _minuesLabel;
}
- (UILabel *)secondsLabel{
if (_secondsLabel == nil) {
_secondsLabel = [[UILabel alloc] init];
_secondsLabel.textAlignment = NSTextAlignmentCenter;
_secondsLabel.textColor = [UIColor whiteColor];
_secondsLabel.font = [UIFont systemFontOfSize:13];
}
return _secondsLabel;
}
@end
在计时器中使用了NSRunLoop来解决时间停止的问题
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 在默认模式下添加的 timer 当我们拖拽 scrollerView 的时候,不会运行 run 方法
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// 在 UI 跟踪模式下添加 timer 当我们拖拽 scrollerView 的时候,run 方法才会运行
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
// timer 可以运行在两种模式下,相当于上面两句代码写在一起
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
UITrackingRunLoopMode:
界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响(操作 UI 界面的情况下运行)
NSRunLoopCommonModes :
这是一个占位用的 Mode,不是一种真正的 Mode (RunLoop无法启动该模式,设置这种模式下,默认和操作 UI 界面时线程都可以运行,但无法改变 RunLoop 同时只能在一种模式下运行的本质)
NSDefaultRunLoopMode :
App 的默认 Mode,通常主线程是在这个 Mode 下运行(默认情况下运行)
文中引用了这位同学提供的相关知识<a href="http://www.jianshu.com/p/338594ec008f" title="">http://www.jianshu.com/p/338594ec008f</a>