一.创建Tab Bar Controller和他们的子控制器
1.Tab Bar Controller
在Main.storyboard中选取Tab Bar Controller,并把它拖动进去,可以发现会有一个自带了两个View Controller的Tab Bar Controller出现了。
我们再新建三个View Controller,并从Tab Bar Controller里面右键到子控制器中,选择Relationship Segue中的view controllers:
连接完毕后,我们可以看到,一个Tab Bar Controller控制了五个子控制器。
2.子控制器的底栏
我们选取每一个View Controller的底栏,右方工具栏选择第四项,可以看到这里面有Title和Image,选取我们要的Title和Image就可以了。
这样,我们的Tab Bar Controller和子控制器都成功建立了。
二.实现日期选取器
首先在工具栏选取一个Date Picker和一个Button,并进行相应的布局操作,记得关联相应的方法。这里的Date Picker选择右键,在@interface和@property之间建立一个变量
@interface DatePickerViewController ()
@property (weak, nonatomic) IBOutlet UIDatePicker *datePicker;
@end
然后在初始化的时候把这个datePicker设立一个日期:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSDate *now = [NSDate date];
[self.datePicker setDate: now animated: NO];
}
在触发按钮方法的时候则要显示出这个日期(直接用.date获取这个实例):
- (IBAction)buttonPressed:(UIButton *)sender {
NSDate *date = self.datePicker.date;
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat: @"yyyy-MM-dd HH:mm"];
NSString *theDate = [dateFormat stringFromDate: date];
NSString *msg = [[NSString alloc] initWithFormat: @"The date is %@", theDate];
UIAlertController *alert = [UIAlertController alertControllerWithTitle: @"Date is selected"
message: msg
preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle: @"Yes!"
style: UIAlertActionStyleDefault
handler: nil];
[alert addAction: action];
[self presentViewController: alert
animated: YES
completion: nil];
}
三.实现单滚轮选取器
首先要在.h文件里面声明委托,表明该控制器将遵循这两个协议:
#import
@interface SingleComponentViewController : UIViewController
@end
在.m文件建立两个变量,一个关联到单滚轮选取器,一个是这个程序所用到的列表:
@interface SingleComponentViewController ()
@property (weak, nonatomic) IBOutlet UIPickerView *singlePicker;
@property (strong, nonatomic) NSArray *characterNames;
@end
先初始化这个列表:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.characterNames = @[@"Hoben", @"jp", @"Eric", @"Road", @"WhoWhenHow",
@"GuanGuan", @"CJ", @"Shit"];
}
然后在选取按钮的时候获得索引并打印出来(用selectedRowInComponent):
- (IBAction)buttonPressed:(id)sender {
//获得选取的第一个滚轮的索引
NSInteger row = [self.singlePicker selectedRowInComponent: 0];
//获得索引对应的row
NSString *selected = self.characterNames[row];
NSString *title = [[NSString alloc] initWithFormat: @"You select %@", selected];
UIAlertController *alert = [UIAlertController alertControllerWithTitle: title
message: @"Thank you for choosing"
preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle: @"You're welcome"
style: UIAlertActionStyleDefault
handler: nil];
[alert addAction: action];
[self presentViewController: alert
animated: YES
completion: nil];
}
最后实现协议需要实现的方法:
- (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView {
//选项可以包括多个滚轮,这里为1
return 1;
}
- (NSInteger)pickerView:(nonnull UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
//选项包含多少行数据,这里为count数量
return [self.characterNames count];
}
- (NSString *) pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
//指定滚轮中指定行的数据
return self.characterNames[row];
}
最后要记得将委托关联到相应的文件里面:
四.实现双滚轮选取器
双/多滚轮选取器中,滚轮从左到右的component分别为0,1,2...所以我们选取滚轮选择的内容的时候,一定要注意component的类别。
#define kFillingComponent 0
#define kBreadComponent 1
其他的和单滚轮没什么不同了,无非就是多了一个NSArray而已
- (IBAction)buttonPressed:(id)sender {
NSInteger fillingRow = [self.doublePicker selectedRowInComponent: kFillingComponent];
NSInteger breadRow = [self.doublePicker selectedRowInComponent: kBreadComponent];
NSString *filling = self.fillingTypes[fillingRow];
NSString *bread = self.breadTypes[breadRow];
NSString *msg = [[NSString alloc] initWithFormat: @"Your %@ on %@ bread is ready.",
filling, bread];
UIAlertController *alert = [UIAlertController alertControllerWithTitle: @"Thank you for order"
message: msg
preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle: @"Great!"
style: UIAlertActionStyleDefault
handler: nil];
[alert addAction: action];
[self presentViewController: alert
animated: YES
completion: nil];
}
把相应的委托方法改一改,注意component类别的讨论:
- (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView {
return 2;
}
- (NSInteger)pickerView:(nonnull UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (component == kBreadComponent)
return [self.breadTypes count];
else
return [self.fillingTypes count];
}
- (NSString *) pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (component == kBreadComponent)
return self.breadTypes[row];
else
return self.fillingTypes[row];
}
五.实现字典选取器
在双滚轮的基础上,我们再弄个邮政编码系统出来,要求在不同州会显示不同区间的邮政编码,会有一个states数组和一个zips数组,分别存放着州的名字和邮政编号,利用教材给的stateZips数据,分成这两个数组并显示出来:
@interface DependentComponentViewController ()
@property (strong, nonatomic) NSDictionary *stateZips;
@property (strong, nonatomic) NSArray *states;
@property (strong, nonatomic) NSArray *zips;
@property (weak, nonatomic) IBOutlet UIPickerView *dependentPicker;
@end
我们要先在viewDidLoad里面初始化这些数据,先读取dictionary,再根据字典里面的key和value,获得相对应的州和邮政编码。
NSString *path = [bundle pathForResource: @"statedictionary" ofType: @"plist"];
self.stateZips = [NSDictionary dictionaryWithContentsOfFile: path];
//对列表按字母排序
NSArray *allStates = [self.stateZips allKeys];
NSArray *sortedStates = [allStates sortedArrayUsingSelector: @selector(compare:)];
self.states = sortedStates;
//获得对应的邮政编码数组
NSString *selectedState = self.states[0];
self.zips = self.stateZips[selectedState];
点击按钮触发的事件同样是不变的
- (IBAction)buttonPressed:(id)sender {
NSInteger stateRow = [self.dependentPicker selectedRowInComponent: kStateComponent];
NSInteger zipRow = [self.dependentPicker selectedRowInComponent: kZipComponent];
NSString *state = self.states[stateRow];
NSString *zip = self.zips[zipRow];
NSString *title = [[NSString alloc] initWithFormat: @"You select zip code %@.", zip];
NSString *msg = [[NSString alloc] initWithFormat: @"%@ is in %@.", zip, state];
UIAlertController *alert = [UIAlertController alertControllerWithTitle: title
message: msg
preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle: @"OK"
style: UIAlertActionStyleDefault
handler: nil];
[alert addAction: action];
[self presentViewController: alert
animated: YES
completion: nil];
}
协议前三个方法同样也是不变的:
- (NSInteger) numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 2;
}
- (NSInteger) pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if (component == kStateComponent)
return [self.states count];
else
return [self.stateZips count];
}
- (NSString *) pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (component == kStateComponent)
return self.states[row];
else
return self.zips[row];
}
但是这里多了一个方法,是根据第一个滚轮而变化第二个滚轮的方法:
- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//一旦左侧滚轮发生变化,则右侧也会发生变化
if (component == kStateComponent) {
NSString *selectedState = self.states[row];
self.zips = self.stateZips[selectedState];
//zips数组发生变化之后重新读取zips数组
[self.dependentPicker reloadComponent: kZipComponent];
//并将zips滚轮置零
[self.dependentPicker selectRow: 0
inComponent: kZipComponent
animated: YES];
}
}
六.遇到的坑
1.Tab Bar显示不出底部图片
是这个!不是上面那个栏!
2.plist加载不出来:
原来是我误会了,将plist加载到了Assets.xcassets里面去,path一直报错为nil,后面复制到DataPicker文件夹就可以了。
3.忘记选delegate:
记得这一步!不然是不会生效的!
4.Button点击无反应:
我按书上这样操作之后,发现根本没有用:
后来才发现,要直接在视图中选中Button,直接在ViewController.m里面实现就可以了,根本不用那么麻烦。
5.书上自带的调用date方法显示日期不正确
参考https://blog.csdn.net/mamong/article/details/8487599,把格式改了一下,才正确,好坑啊。。这官方api。