一、创建项目
使用Single View Application创建一个项目,命名为Date。
1、添加DateChooserViewController类
用于显示日期选择器并且在用户选择的时候作出响应,类似上个项目,添加一个新的类,Create完成。
2、添加Date Chooser场景并关联视图控制器
在IB中打开MainStoryboard.storyboard,将一个视图控制器添加到IB的空白区域(或文档大纲区域)。为了将新增的视图控制器关联到新建的类,在文档大纲区域选择第二个场景的View Controller图标,打开属性,从Class下拉列表中选择DateChooserViewController。
二、设计界面
1、从对象库中拖动一个工具栏到第一个视图的底部,默认情况下工具栏只有一个item的按钮。双击该item,修改文字为:选择日期。接下来,从对象库中拖动2个灵活间距栏按钮项(Flexible Space Bar Button Item)到工具栏中,分别放在“选择日期”的两边,调整长短到合适即可。
2、然后在第一个视图中间添加一个Label,居中显示,设置默认文字为:“没有选择”。
3、设置第一个视图的背景色为Scroll View Texted Background Color。
4、选择第二个视图,添加一个日期选择器,一个Label,一个按钮。
三、创建切换
按住Control键,从初始视图拖动到第二个视图(直接在视图上面拉线我怎么老失败,在文档大纲区域,反而成功???),选择Modal。这时候初始场景中将增加一行,内容为Segue from UIViewController to DateChooserViewController,选择这行,打开属性,配置该切换:
给切换指定标示符:toDateChooser。由于将要手工切换,因此将标示符设置为该值很重要。
务必指定锚:
对于在两个视图控制器之间创建的弹出切换,必须设置锚。如果不设置,程序也能运行,但是单击触发切换的按钮后,程序将崩溃。
四、创建并连接输出口和操作
1、添加输出口
1)、选择第一个场景的输出标签,创建一个名为outputLabel的输出口,用于在第一个场景中显示日期计算结果;
2、添加操作
1)、选择第一个场景,创建工具栏中间的“选择日期”按钮的操作showDateChooser,用于显示第二个场景;
2)、选择第二个场景,创建日期选择器的操作setDateTime,并将触发其Value Changed事件;
3)、选择第二个场景,创建完成按钮的操作dismissDateChooser,返回到第一个场景。
五、实现场景切换逻辑
1、导入接口文件
在ViewController.h文件,添加如下代码:
#import "DateChooserViewController.h"
在新增的类的.h文件中,添加如下代码:
#import "ViewController.h"
2、创建并设置属性delegate
除了让这两个类能互相知道对方提供的属性和方法之外,还需提供一个属性,让日期选择器视图控制器能够访问初始场景的视图控制器。
对于模态类型,可以使用DateChooserViewController的属性presentingViewController来获取初始场景的视图控制器,但是该属性不适用于ipad独有的弹出框。为了保持模态实现和弹出框的实现一致,在类DateChooserViewController.h中添加如下代码:
@property (strong, nonatomic) id delegate;
定义了一个类型为id的属性,可以指向任何对象。然后在其对应的.m文件,添加如下代码:
@synthesize delegate;
设置属性delegate:在ViewController.m中实现,当初始场景和日期选择场景之间的切换被触发时会调用这个方法。
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { ((DateChooserViewController *)segue.destinationViewController).delegate = self; }
通过上述代码,将参数segue的属性destinationViewController强制转换为一个DateChooserController,并将其delegate属性设置为self,即初始场景的ViewController类的当前实例。
属性delegate提供了一种交换信息的机制。
3、处理初始场景和日期选择场景之间的切换
本项目中,切换是在两个视图之间,而不是前面的对象和视图控制器之间创建的。
这称为手工切换,因为需要在方法中使用代码来触发。在触发时,首先检查是否显示了日期选择器,通过一个布尔值来判断。在ViewController.h和.m文件分别添加如下代码:
@property (nonatomic) Boolean dateChooserVisible;
@synthesize dateChooserVisible;
因为布尔型不是对象,因此不须要使用关键字strong,也不用在使用完后置为nil。
然后在ViewConyroller.m文件实现showDateChooser方法:
首先核实属性dateChooserVisible不为YES,再调用performSegueWithIdentifier:sender启动到日期选择场景的切换。然后设置布尔值为YES,以便了解当前显示了日期选择场景。
- (IBAction)showDateChooser:(id)sender { if(self.dateChooserVisible!=YES){ [self performSegueWithIdentifier:@"toDateChooser" sender:sender]; self.dateChooserVisible = YES; } }
另外,在第二个场景点击确定按钮,回到第一个场景:
- (IBAction)dismissDateChooser:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; }
六、实现日期计算逻辑
1、获取当前日期
创建并初始化一个NSDateFormatter对象,然后使用该对象的setDateFormat方法和一个模式字符串创建一种自定义格式,最后调用NSDateFormatter的另一个方法stringFromDate将这种格式应用到日期。
2、计算两个日期相差多少天
使用NSDate对象的实例方法timeIntervalSinceDate实现,返回两个日期相差多少秒。
3、实现日期计算和显示
1)、在ViewController.h文件,添加如下代码:
-(void) calculateDateDifference:(NSDate *)chosenDate;
2)、在ViewController.m文件实现:
//计算日期差值 -(void)calculateDateDifference:(NSDate *)chosenDate{ NSDate *todaysDate; NSString *differenceOutput; NSString *todaysDateString; NSString *chosenDateString; NSDateFormatter *dateFormat; NSTimeInterval difference; //把当前日期时间存储到todaysDate todaysDate = [NSDate date]; //计算时间差 difference = [todaysDate timeIntervalSinceDate:chosenDate] / 86400; //创建一个新的日期格式器对象,用于格式化todaysDate和chosenDate dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat:@"MMMM d, yyyy hh:mm:ssa"]; //使用todaysDateString存储当前日期 todaysDateString = [dateFormat stringFromDate:todaysDate]; chosenDateString = [dateFormat stringFromDate:chosenDate]; differenceOutput = [[NSString alloc] initWithFormat: @"选择的日期(%@)和今天(%@)相差:%1.2f天", chosenDateString, todaysDateString, fabs(difference)]; self.outputLabel.text = differenceOutput; }
4、输出更新
在两个地方需要调用calculateDateDifference方法:用户选择日期、显示日期选择场景时。在第二种情况时,用户还没有选择日期,选择器显示的是当前日期。
1)、对用户的操作响应:在方法setDateTime中调用,计算两个日期的差值,它在日期选择器的值发生变化时调用。在DateChooserViewController.m中实现:
- (IBAction)setDateTime:(id)sender { [(ViewController *)delegate calculateDateDifference:((UIDatePicker *)sender).date]; }
这样通过属性delegate来访问ViewController.m中的方法calculateDateDifference,并将日期选择器的date属性传递给这个方法。但是如果用户在没有显式地选择日期选择器的情况下返回,则不会进行日期计算。
在这种情况下,可假定用户选择的是当前日期。在DateChooserViewController.m中:
-(void)viewDidAppear:(BOOL)animated{ [(ViewController *)self.delegate calculateDateDifference:[NSDate date]]; }
七、运行项目