显示启用/禁用时间单位的倒计时

时间:2014-01-22 17:22:28

标签: ios objective-c cocoa-touch nscalendar nsdatecomponents

这个问题基本上是关于自定义日期格式。我设法开发了一个倒计时应用程序,该应用程序设法创建一个事件,以后可以由客户查看,定制或跟踪。重要的部分是倒数计时器,它从数据库中获取秒数并根据日期格式化程序显示剩余时间。到目前为止,我在应用程序中使用默认设置,计数器格式为dd:hh:mm,显然我的客户希望允许应用程序用户自定义时间显示方式。所以现在用户可以选择四个选项,例如yy:周:hh:mm或月:周:天:小时。我认为最好的方法是将表四个索引保存为db作为字符串。我的问题出现在日历上。

conversionInfo = [sysCalendar components:NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSSecondCalendarUnit fromDate:today  toDate:future  options:0];

        one = [NSString stringWithFormat:@"%d Days %d Hours %d Minutes %d Seconds %@", [conversionInfo day], [conversionInfo hour],[conversionInfo minute],[conversionInfo second], untilOrSince]; self.eventTimer.text = one;

conversionInfo = [sysCalendar components: NSHourCalendarUnit | NSSecondCalendarUnit fromDate:today  toDate:future  options:0];

        one = [NSString stringWithFormat:@"%ld Seconds %@", (long)[conversionInfo second], untilOrSince];

此外,如果我使用所有单位构建日历但仅显示秒数,那么倒计时将仅显示59秒而不是343746545秒直到 The counter

例如,这些日历单位不能放在一个数组中,那么如果用户选择2,4,5,6这将是几个月:天:小时:分钟,我将如何选择日历格式?我不能说components = [NSArray arrayWithObjects: [arrComponents objectAtIndex:2], [arrComponents objectAtIndex:2],nil];

User options

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

好的,这比我最初的想法更难


在整个系统中,单位标志用于将日期定义为组件等。这个单元缺陷可以只用一个值,一个位掩码组合。我将它用于我的代码。

年份单位可能为0....000010 月份单位可能为0....000100

两者的位掩码都是

  0....000010    NSCalendarUnitYear
  0....000100    NSCalendarUnitMonth
 ------------
& 0....000110

因此,要保存一个单位的信息,我们只需要将相应的位设置为1

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.selectedUnitsBitmask= 0;
    self.unitNames = @[ @"Year", @"Month", @"Week", @"Day", @"Hour", @"Minute", @"Second"];
    self.units = @[@(NSCalendarUnitYear), @(NSCalendarUnitMonth), @(NSCalendarUnitWeekOfMonth), @(NSCalendarUnitDay), @(NSCalendarUnitHour), @(NSCalendarUnitMinute), @(NSCalendarUnitSecond)];


    NSDateComponents *c = [[NSDateComponents alloc] init];
    c.year = 2014;
    c.month = 12;
    c.day = 25;

    self.futureDate = [[NSCalendar currentCalendar] dateFromComponents:c];
}

self.unitNames的值用于填充表格视图 self.units存储每个可用单元的单位标志。

-(UITableViewCell *)tableView:(UITableView *)tableView
        cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier =@"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    cell.textLabel.text = _unitNames[indexPath.row];


    NSUInteger s;
    NSUInteger row = indexPath.row;
    s = NSIntegerMax & [self.units[row] integerValue];
    cell.accessoryType = (self.selectedUnitsBitmask & s) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
    return cell;

}

如果选择了一个单元格,s = NSIntegerMax & [self.units[row] integerValue];将检查位掩码,如果要使用此单位。

如果选择了一个单元格,我们想要切换它所代表的单位的位

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSUInteger s;
    NSUInteger row = indexPath.row;
    s = NSIntegerMax & [self.units[row] integerValue];
    self.selectedUnitsBitmask ^= s ;
    NSLog(@"%lu, %lu", (unsigned long)s, (unsigned long)self.selectedUnitsBitmask);

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType =(self.selectedUnitsBitmask & s) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
    [self updateCountDownLabel:nil];
}

下面

NSUInteger s;
NSUInteger row = indexPath.row;
s = NSIntegerMax & [self.units[row] integerValue];

s表示所选的位,

self.selectedUnitsBitmask ^= s ;

将在位掩码中切换它。 bitmask ^= sbitmask = bitmask ^ s的缩写形式,其中^是独占或:位掩码的第n位必须与s的第n位相反

  0011    bitmask
^ 0101    s
  ----
= 1100

现在我们可以根据位掩码中的单位标志更新将打印时差的字符串:

- (IBAction)updateCountDownLabel:(id)sender {

    BOOL includeYear  = self.selectedUnitsBitmask & NSCalendarUnitYear;
    BOOL includeMonth = self.selectedUnitsBitmask & NSCalendarUnitMonth;
    BOOL includeDay   = self.selectedUnitsBitmask & NSCalendarUnitDay;
    BOOL includeHour  = self.selectedUnitsBitmask & NSCalendarUnitHour;
    BOOL includeMinute= self.selectedUnitsBitmask & NSCalendarUnitMinute;
    BOOL includeSecond= self.selectedUnitsBitmask & NSCalendarUnitSecond;

    NSDateComponents *diffDateComponents = [[NSCalendar currentCalendar] components:self.selectedUnitsBitmask fromDate:[NSDate date] toDate:self.futureDate options:0];

    NSMutableString *outputString = [@"" mutableCopy];
    if (includeYear && diffDateComponents.year)
        [outputString appendFormat:@"%d Year", diffDateComponents.year];
    if (includeMonth && diffDateComponents.month)
        [outputString appendFormat:@" %d Month", diffDateComponents.month];
    if (diffDateComponents.weekOfMonth < NSIntegerMax && diffDateComponents.weekOfMonth)
        [outputString appendFormat:@" %d Week", diffDateComponents.weekOfMonth];
    if (includeDay && diffDateComponents.day)
        [outputString appendFormat:@" %d Day", diffDateComponents.day];
    if (includeHour && diffDateComponents.hour)
        [outputString appendFormat:@" %d Hour", diffDateComponents.hour];
    if (includeMinute && diffDateComponents.minute)
        [outputString appendFormat:@" %d Minute", diffDateComponents.minute];
    if (includeSecond && diffDateComponents.second)
        [outputString appendFormat:@" %d Second", diffDateComponents.second];




    self.countDownLabel.text = [outputString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

}

要确定是否设置了标记,我们使用& AND运算符

BOOL includeYear  = self.selectedUnitsBitmask & NSCalendarUnitYear;

如果年份标志为0....000010

并且位掩码包含0....010110

&操作将返回

  0....000010    NSCalendarUnitYear
& 0....010110    bitmask
-------------
= 0....000010    -> NSCalendarUnitYear

我们为所有单位执行此操作。我不知道为什么,但&amp;操作总是返回0。在这里我们使用hack:

if (diffDateComponents.weekOfYear < NSIntegerMax)
    [outputString appendFormat:@" %d Week", diffDateComponents.weekOfYear];

对于新的NSDateComponents week,使用可用整数NSIntegerMax表示的最大数字进行实例化。如果它的值小于NSIntegerMax,我们假设它已设置,我们将它附加到字符串。


结果:

enter image description here


整个守则整体:


#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UILabel *countDownLabel;
@property (nonatomic) NSInteger selectedUnitsBitmask;
@property (strong, nonatomic) NSArray *unitNames;
@property (strong, nonatomic) NSArray *units;
@property (strong, nonatomic) NSDate *futureDate;


- (IBAction)updateCountDownLabel:(id)sender;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.selectedUnitsBitmask= 0;
    self.unitNames = @[ @"Year", @"Month", @"Week", @"Day", @"Hour", @"Minute", @"Second"];
    self.units = @[@(NSCalendarUnitYear), @(NSCalendarUnitMonth), @(NSCalendarUnitWeekOfMonth), @(NSCalendarUnitDay), @(NSCalendarUnitHour), @(NSCalendarUnitMinute), @(NSCalendarUnitSecond)];


    NSDateComponents *c = [[NSDateComponents alloc] init];
    c.year = 2014;
    c.month = 12;
    c.day = 25;

    self.futureDate = [[NSCalendar currentCalendar] dateFromComponents:c];
}



-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.units count];
}

-(UITableViewCell *)tableView:(UITableView *)tableView
        cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier =@"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    cell.textLabel.text = _unitNames[indexPath.row];

    NSUInteger s;
    NSUInteger row = indexPath.row;
    s = NSIntegerMax & [self.units[row] integerValue];
    cell.accessoryType = (self.selectedUnitsBitmask & s) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;


    return cell;

}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSUInteger s;
    NSUInteger row = indexPath.row;
    s = NSIntegerMax & [self.units[row] integerValue];
    self.selectedUnitsBitmask ^= s ;
    NSLog(@"%lu, %lu", (unsigned long)s, (unsigned long)self.selectedUnitsBitmask);

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType =(self.selectedUnitsBitmask & s) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
    [self updateCountDownLabel:nil];
}

- (IBAction)updateCountDownLabel:(id)sender {

    BOOL includeYear  = self.selectedUnitsBitmask & NSCalendarUnitYear;
    BOOL includeMonth = self.selectedUnitsBitmask & NSCalendarUnitMonth;
    BOOL includeDay   = self.selectedUnitsBitmask & NSCalendarUnitDay;
    BOOL includeHour  = self.selectedUnitsBitmask & NSCalendarUnitHour;
    BOOL includeMinute= self.selectedUnitsBitmask & NSCalendarUnitMinute;
    BOOL includeSecond= self.selectedUnitsBitmask & NSCalendarUnitSecond;

    NSDateComponents *diffDateComponents = [[NSCalendar currentCalendar] components:self.selectedUnitsBitmask fromDate:[NSDate date] toDate:self.futureDate options:0];

    NSMutableString *outputString = [@"" mutableCopy];
    if (includeYear && diffDateComponents.year)
        [outputString appendFormat:@"%d Year", diffDateComponents.year];
    if (includeMonth && diffDateComponents.month)
        [outputString appendFormat:@" %d Month", diffDateComponents.month];
    if (diffDateComponents.weekOfMonth < NSIntegerMax && diffDateComponents.weekOfMonth)
        [outputString appendFormat:@" %d Week", diffDateComponents.weekOfMonth];
    if (includeDay && diffDateComponents.day)
        [outputString appendFormat:@" %d Day", diffDateComponents.day];
    if (includeHour && diffDateComponents.hour)
        [outputString appendFormat:@" %d Hour", diffDateComponents.hour];
    if (includeMinute && diffDateComponents.minute)
        [outputString appendFormat:@" %d Minute", diffDateComponents.minute];
    if (includeSecond && diffDateComponents.second)
        [outputString appendFormat:@" %d Second", diffDateComponents.second];


    self.countDownLabel.text = [outputString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

}

答案 1 :(得分:-1)

您可以使用stringByAppendingString:

NSString formattedDate = @"";
formattedDate = [formattedDate stringByAppendingString:[NSString stringWithFormat:@"%d Days", [conversionInfo day]]];
formattedDate = [formattedDate stringByAppendingString:[NSString stringWithFormat:@"%d Hours", [conversionInfo hour]]];
///....

答案 2 :(得分:-1)

感谢您的所有答案,我感谢他们。

在你回复之前,我想到了我自己的解决方案,它可能不像vikingosegundo那样详细和理解,但它有效,可以扩展。

首先从检查表中将四个数字作为字符串存储到数据库中。这允许我使用“事件”存储格式信息。每次我想获得格式化我需要获取字符串并更改为数组:

int option = 0;
unsigned int unitFlags = 0;
NSString *input = self.detailItem.prefs;
NSArray *myWords = [input componentsSeparatedByString:@","];

for (int fuu = 0; fuu < myWords.count; fuu++) {

    option = [[myWords objectAtIndex:fuu]intValue];
    switch (option)
    {
        case 0:

            unitFlags = unitFlags | NSYearCalendarUnit;
            break;

        case 1:

            unitFlags = unitFlags | NSMonthCalendarUnit;
            break;

        case 2:

            unitFlags = unitFlags | NSWeekCalendarUnit;
            break;

        case 3:
            unitFlags = unitFlags | NSDayCalendarUnit;
            break;

        case 4:

            unitFlags = unitFlags | NSHourCalendarUnit;
            break;

        case 5:
            unitFlags = unitFlags | NSMinuteCalendarUnit;
            break;
            }
}

正如你所看到的,我正在根据数组中的whats构建我的单位标志。

现在我需要如何构建日历,但我怎么知道组件和格式是什么?

以下是答案:

NSString *prularity = @"";

if ([future compare:today] == NSOrderedAscending ) {

    conversionInfo = [sysCalendar components:unitFlags fromDate:future  toDate:today  options:0];

    untilOrSince = @"since";


} else {

    conversionInfo = [sysCalendar components:unitFlags fromDate:today  toDate:future  options:0];

    untilOrSince = @"until";

}

在这里,我使用所选单位构建我的日历,我也计算日期或日期。

最后,我只需要根据所选内容进行格式化:

for (int fuu = 0; fuu < myWords.count; fuu++) {

    option = [[myWords objectAtIndex:fuu]intValue];

    switch (option)
    {
        case 0:

            if ([conversionInfo year] >= 2 || [conversionInfo year] == 0) {
                prularity = @"YEARS";
            } else {
                prularity = @"YEAR";
            }
            one = [one stringByAppendingString:[NSString stringWithFormat:@"%ld %@ ", (long)[conversionInfo year], prularity]];
            break;

        case 1:
            if ([conversionInfo month] >= 2|| [conversionInfo month] == 0) {
                prularity = @"MONTHS";
            } else {
                prularity = @"MONTH";
            }
            one = [one stringByAppendingString:[NSString stringWithFormat:@"%ld %@ ", (long)[conversionInfo month], prularity]];
            break;

        case 2:
            if ([conversionInfo week] >= 2 || [conversionInfo week] == 0) {
                prularity = @"WEEKS";
            } else {
                prularity = @"WEEK";
            }
            one = [one stringByAppendingString:[NSString stringWithFormat:@"%ld %@ ", (long)[conversionInfo week], prularity]];
            break;

        case 3:
            if ([conversionInfo day] >= 2 || [conversionInfo day] == 0) {
                prularity = @"DAYS";
            } else {
                prularity = @"DAY";
            }
            one = [one stringByAppendingString:[NSString stringWithFormat:@"%ld %@ ", (long)[conversionInfo day], prularity]];
            break;

        case 4:
            if ([conversionInfo hour] >= 2 || [conversionInfo hour] == 0) {
                prularity = @"HOURS";
            } else {
                prularity = @"HOUR";
            }
            one = [one stringByAppendingString:[NSString stringWithFormat:@"%ld %@ ", (long)[conversionInfo hour], prularity]];
            break;

        case 5:
            if ([conversionInfo minute] >= 2 || [conversionInfo minute] == 0) {
                prularity = @"MINUTES";
            } else {
                prularity = @"MINUTE";
            }
            one = [one stringByAppendingString:[NSString stringWithFormat:@"%ld %@ ", (long)[conversionInfo minute], prularity]];
            break;
    }

}

打印我的柜台:

one = [one stringByAppendingString:[NSString stringWithFormat:@" %@",untilOrSince]];
self.eventTimer.text = one;

希望这可以帮助有类似问题的人。我知道这不是最好的解决方案,但到目前为止它还有效。