UIPickView 和 UIDatePicker

时间:2023-03-09 05:25:51
UIPickView 和 UIDatePicker

*:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }

a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }

h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;
text-decoration: none; }

h1 tt, h1 code {
font-size: inherit; }

h2 tt, h2 code {
font-size: inherit; }

h3 tt, h3 code {
font-size: inherit; }

h4 tt, h4 code {
font-size: inherit; }

h5 tt, h5 code {
font-size: inherit; }

h6 tt, h6 code {
font-size: inherit; }

h1 {
font-size: 28px;
color: black; }

h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }

h3 {
font-size: 18px; }

h4 {
font-size: 16px; }

h5 {
font-size: 14px; }

h6 {
color: #777777;
font-size: 14px; }

p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }

hr {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0;
}

body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }

h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }

li p.first {
display: inline-block; }
li {
margin: 0; }
ul, ol {
padding-left: 30px; }

ul :first-child, ol :first-child {
margin-top: 0; }

dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }

blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }

table {
padding: 0;border-collapse: collapse; }
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }

img {
max-width: 100%; }

span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }

code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }

pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }

.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }

pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }

sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:0 auto;
}
}
@media print {
table, pre {
page-break-inside: avoid;
}
pre {
word-wrap: break-word;
}
}
-->

UIPickView 和 UIDatePicker

  • 1.UIPickView什么时候用?
    • 通常在注册模块,当用户需要选择一些东西的时候,比如说城市,往往 弹出一个PickerView给他们选择。
  • 2.UIPickView常见用法
    • 独立的,没有任何关系 =>菜单系统。
    • 相关联的,下一列和第一列有联系=>省会城市选择
    • 图文并茂,=>国旗选择。
  • 3.UIDatePicker什么时候用?
    • 当用户选择日期的时候,一般弹出一个UIDatePicker给用户选择。

01-UIPickView的基本使用

  • UIPickView和TableView一样,想要展示数据也要设置数据源和代理
  • 设置数据源
    • self.pickView.dataSource = self;
  • 设置代理
    • self.pickView.delegate = self;
  • 遵守数据源,代理协议:

    @interface ViewController () <UIPickerViewDataSource,UIPickerViewDelegate>
    @property (weak, nonatomic) IBOutlet UIPickerView *pickView;
    @end
  • 实现数据源代理方法:

    总共有多少列
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 3; } 第component列有多少行.
    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    return 4; } 返回每一列的宽度
    - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent: (NSInteger)component{
    } 返回第几列的高度
    - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
    return 50; } 返回每一列的标题
    - (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    return @"gaowei"; } 返回每一列的视图UIView
    - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow: (NSInteger)row forComponent:(NSInteger)component reusingView: (nullable UIView *)view{
      UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
    return btn; }

02-UIPickView简单Demo

  • import "ViewController.h"
  • @interface ViewController ()<UIPickerViewDataSource,UIPickerViewDelegate>
    //展示数据的pickView
    @property (weak, nonatomic) IBOutlet UIPickerView *pickView; //数组当中有3个数组,每个数组代表一列.每一列数组的个数代表这列有多少行.
    @property(nonatomic,strong) NSArray *foodArray; //显示当前选中的食物
    @property (weak, nonatomic) IBOutlet UILabel *foodLabel;
    @end @implementation ViewController
    //懒加载数据
    -(NSArray *)foodArray{
    if (_foodArray == nil) { //获取Plist文件的路径
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"foods.plist" ofType:nil];
    //从Plist文件当中加载数组.
    _foodArray = [NSArray arrayWithContentsOfFile:filePath];
    }
    return _foodArray;
    } - (void)viewDidLoad {
    [super viewDidLoad];
    //设置数据源和代理
    self.pickView.dataSource = self;

    self.pickView.delegate = self;
    } //总共有多少列
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{ //数组当中有几个元素, 就展示多少列.每个元素代表一列,
    return self.foodArray.count; }
    //第component列有多少行.
    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component{
    //取出当前所在的列.每一列都是一个数组.
    NSArray *array = self.foodArray[component]; 返回每一组当中, 每个数组的个数, 也就是这组有多少行.
    return array.count;
    } 返回每一行的标题
    - (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:
    (NSInteger)row forComponent:(NSInteger)component{
    //取出当前所在的列.每一列都是一个数组.
    NSArray *componentArray = self.foodArray[component];
    //返回数组当中每一个元素
    return componentArray[row];
    } //点击了哪列的哪一行
    - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    NSString *food = self.foodArray[component][row]; self.foodLabel.text = food;
    }

03-拦截用户输入

- 通过设置代理的方式来去监听文件框的改变

    //是否允许开始编辑
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{ return YES;
} //开始编辑时调 ,(弹出键盘)became first responder
- (void)textFieldDidBeginEditing:(UITextField *)textField{
NSLog(@"弹出键盘");
} //是否允许结束编辑.
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
   return YES;
} //结束编辑时调用.
- (void)textFieldDidEndEditing:(UITextField *)textField{
    NSLog(@"结束编辑时调用.");
} //是否允许文字改变.
//拦截用户输入.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
  return NO;
}

04- 定义国旗键盘

  • 运行例效果:

  • UIPickView 和 UIDatePicker
    • 点击国家时弹出的是一个国旗键盘.
    • 实现这种效果采取的方案是自定义一个TextField.修改它的弹出键盘为 个UIPickView.

    • 对应的模型:

    • UIPickView 和 UIDatePickerUIPickView 和 UIDatePicker

    • #import <UIKit/UIKit.h>
      注意:这里继承的是UITextField
      @interface FlagField : UITextField
      @end //这个是自定义的pickView每一行的一个UIView.
      #import "FlagView.h"
      #import "FlagItem.h"//这个是每一行对应的模型.
      @interface FlagField()<UIPickerViewDataSource,UIPickerViewDelegate>
      //保存加载的过期数组.
      @property(nonatomic,strong) NSMutableArray *flagArray;
      @end @implementation FlagField
      //加载数据
      //数据内容对应的模型图:
      UIPickView 和 UIDatePicker
      //数组当中保存的都是字典.我们看到字典就会它转成模型.
      所以新建了一个 FlagItem模型,FlagItem每一个属性,都对应着字典当中的key值.
      //懒加载数据
      -(NSMutableArray *)flagArray{
      if (_flagArray == nil) {
      //加载plist 件路径
      NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
      //根据路径从plist文件当中加载数组
      NSArray*dictArray =[NSMutableArrayarrayWithContentsOfFile:filePath];
      //创建数组
      _flagArray = [NSMutableArray array];
      for (NSDictionary *dict in dictArray) {//遍历数组当中的每一个元素,数组当中保存的都是字典.
      //把字典转成FlagItem模型
      FlagItem *item = [FlagItem flagItemDict:dict];
      //把模型添加到数组当中
      [_flagArray addObject:item]; }
      }
      return _flagArray;
      }
      注意:这个地方做了两个初始化,目的是为了不论别人使用这个FlagField是从xib创建,还是从代码创建,都让它做初始化.
      //从xib当中创建
      -(void)awakeFromNib{
      //初始化.
        [self setUp];
      }
      //从代码创建
      - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]) {
        //初始化.
          [self setUp];
      }
        return self;
      } //初始化.
      - (void)setUp{
      //创建UIPickerView
      UIPickerView *pick = [[UIPickerView alloc] init];
      //设置代理
      pick.delegate = self;
      //设置数据源
      pick.dataSource = self; self.inputView = pick;
      } //数据源方法
      //总共有多少列.
      -(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
      return 1; } //总共有多少行
      -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ 看数组当中有多少个模型,就有多少行.
      return self.flagArray.count; }
      //设置每一行的高度
      -(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{ 这个 度就是xib当中描述的View的 度
      return 90;
      }
      返回每一行的控件.这里的控件是一个UIView.通过Xib描述的模型.
      -(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(
      //快速创建一个FlagView
      FlagView *flagV = [FlagView flagView];
      //取出当前行对应的模型
      FlagItem *item = self.flagArray[row]; 把模型赋值给FlagView的item属性,就会调用FlagItem的set方法,在set方法当中给FlagItem当中的子控件进行赋值.
      flagV.flagItem = item; 返回FlagView视图. return flagV;
      }
    • 执行过程:
    • UIPickView 和 UIDatePicker

      05-KVC模型改进- 定义国旗键盘

  • 在给 FlagView成员属性赋值的时候,发现在这里还得要自己去写UIImage, 手动去创建UIImage ,一般在模型当中保存的就是控件最想要的东西.那个这个地方,我们最好在模型当中提供的是一张图片.

    -(void)setFlagItem:(FlagItem *)flagItem{ _flagItem = flagItem;
    //给属性赋值.
    //设置名称
    self.name.text = flagItem.name;
    //设置图片.
    self.imageV.image = [UIImage imageNamed:flagItem.icon];
    }
  • 所以在这里进行改进模型,让模型当中存放的就是用户最想要的东西. 改过之后会导致一个问题,在KVC给属性赋值的时候,字典当中给的是一个字符串.这样在转的过程当中就会造成类型不匹配,发生错误.

  • 这个时候我们就要看下KVC的底层实现原理,看过后,然后通过它的特性,去避免这个问题

  • 这个是最初的字典转模型的方法.

    +(instancetype)flagItemDict:(NSDictionary *)dict{
    //创建对象
    FlagItem *item = [[self alloc] init];
    //通过KVC给对象的属性赋值.
    [item setValuesForKeysWithDictionary:dict];
    //返回 个赋值好属性的对象.
    return item;
    } //通过KVC,调用对象的[item setValuesForKeysWithDictionary:dict]
    setValuesForKeysWithDictionary:底层实现就是遍历字典当中的所有Key和Value值.给对应的key,value赋值
    [dictenumerateKeysAndObjectsUsingBlock:^(id _Nonnullkey,id _Nonnull obj, BOOL * _Nonnull stop) {
    //给对应的key,value赋值
    [item setValue:obj forKeyPath:key];
    }];
  • setValue:forKeyPath:的底层实现:

    1.它会调用这个属性的set方法.
    2.如果没有set方法,它会去判断有没有跟key值同名的成员属性.如果有,就直接赋值,icon = obj.
    3.如果没有,那么它还会去判断有没有跟key值名相同带有下划线的成员属性,如果有,就直接赋值,_icon = obj.
    4.如果都没有, 就直接报错.找不到对应的成员属性.
    利用KVC会调用属性的set方法. 当给icon属性赋值时,把传进来的字符串当作图片的名称,创建一个图片,再给图片进行赋值.
    这个的参数,类型是可以改的
    - (void)setIcon:(NSString *)icon{
    UIImage *image = [UIImage imageNamed:icon];
    _icon = image;
    } 那在View当中就可以直接赋值图片了.
    -(void)setFlagItem:(FlagItem *)flagItem{
    _flagItem = flagItem; 给属性赋值.
      self.name.text = flagItem.name; //设置名称
      //self.imageV.image = [UIImage imageNamed:flagItem.icon]; 模型当中保存的应该是最想的东西,所以在模型当中保存的应该是图片.
      self.imageV.image = flagItem.icon;//设置图片.
    }

    06-自定义生日键盘

    运行示例效果:

  • UIPickView 和 UIDatePicker

    • 点击生日时弹出的是一个日期键盘. 实现这种效果采取的方案是自定义一个TextField.修改它的弹出键盘为一个 UIDatePicker.

  • #import <UIKit/UIKit.h> 注意:这 继承的是UITextField
    @interface BirthDayField : UITextField
    @end #import "BirthDayField.h"
    @implementation BirthDayField
    注意:这个地方做了两个初始化,目的是为了不论别人使用这个FlagField是从xib创建,还是从代码创建,都让它做初始化.
    //从xib当中创建
    -(void)awakeFromNib{
    //初始化.
    [self setUp];
    } //从代码创建
    - (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
    //初始化.
    [self setUp];
    }
    return self;
    } //初始化方法
    - (void)setUp{
    //创建UIDatePicker(日期键盘)
      UIDatePicker *pick = [[UIDatePicker alloc] init];
      pick.datePickerMode = UIDatePickerModeDate; ISO639语 编码(中国zh -zhongwen)
      NSLocale *local = [NSLocale localeWithLocaleIdentifier:@"zh"];
      pick.locale = local;
    //UIDatePicker没有代理方法
    //监听UIDatePicker的值改变.
      [pick addTarget:self action:@selector(dateChange:)forControlEvents:UIControlEventValueChanged];
    // 定义键盘, 让弹出的键盘是 个UIPickerView.( 定义的键盘是不需要设置尺寸的.)
      self.inputView = pick;
    } //当日期改变时调
    - (void)dateChange:(UIDatePicker *)datePick{
    //把日期转成字符串.
        NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    //设置日期格式
        fmt.dateFormat = @"yyyy-MM-dd";
    //格式化日期.
        NSString *dateString = [fmt stringFromDate:datePick.date];
    //给日期文本框赋值.
        self.text = dateString;
    }
    @end

    07- 定义城市键盘

    #import <UIKit/UIKit.h>
    注意:这里继承的是UITextField
    @interface CityTextField : UITextField
    @end #import "CityTextField.h"
    省模型
    #import "ProvincesItem.h"
    @interface CityTextField()<UIPickerViewDataSource,UIPickerViewDelegate>
    //省份数组.装的都是ProvincesItem模型.
    @property(nonatomic,strong) NSMutableArray *provincesDataArray;
    //记录当前选中的是哪一个省份的角标.
    @property(nonatomic, assign) NSInteger curProIndex;
    @end
  • 加载数据

  • 数据内容对应的模型图:

  • UIPickView 和 UIDatePicker
  • 数组当中保存的都是字典.我们看到字典就会它转成模型.

  • 所以新建了一个 ProvincesItem模型,ProvincesItem每一个属性,都对应着字典当中的key值.

    懒加载省份数据
    -(NSMutableArray *)provincesDataArray{
    if (_provincesDataArray == nil) {
    //创建数组
    _provincesDataArray = [NSMutableArray array];
    //获取plist文件的路径
    NSString*filePath= [[NSBundlemainBundle]pathForResource:@"provinces.plist" ofType:nil];
    //从plist 文件当中加载数据
    NSArray *tempArray = [NSArray arrayWithContentsOfFile:filePath];
    //遍历数组当中的每一个元素.每个元素都是一个字典,把字典转成模型
    for (NSDictionary *dict in tempArray) {
    //创建省份模型对象.快速的将字典转成模型
    ProvincesItem*item= [ProvincesItemprovincesItemWithDict:dict]; 把转好的对象保存到数组当中.
    [_provincesDataArray addObject:item]; }
    }
    return _provincesDataArray;
    } -(void)awakeFromNib{
    //初始化.
    [self setUp];
    } - (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
    //初始化.
    [self setUp];
    }
    return self;
    }
    //初始化方法
    - (void)setUp{
    //创建UIPickerView
    UIPickerView *pickV = [[UIPickerView alloc] init];
    //设置代理
    pickV.delegate = self;
    //设置数据源.
    pickV.dataSource = self;
    //设置弹出键盘是一个UIPickerView
    self.inputView = pickV;
    } 实现代理协议方法
    //总共有多少组
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    //总共有两组
    return 2;
    }
    //每组有多少行
    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    //第一组展有多少行,由省份数组决定, 数组当中有多少个省份模型,第一组就有多少行.
    if (component == 0) {
    return self.provincesDataArray.count;
    }else{
    //第二组展有多少行,由当前选中的省份决定,当前选中哪个省份.哪个省份下的城市数组决定. 所以要先获取当前先中的是哪个省.
    ProvincesItem *proItem = self.provincesDataArray[self.curProIndex];
    //返回当前省份下城市的个数
    return proItem.cities.count;
    }
    } 返回每一行展示的标题
    - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    如果是第0列,就是省份,返回省份的名称 if (component == 0) {
    ProvincesItem *proItem = self.provincesDataArray[row];
    return proItem.name;
    }else{
    先取出选中的省份.
    ProvincesItem *proItem = self.provincesDataArray[self.curProIndex];
    //返回选中省份下,每个城市.
    return proItem.cities[row];
    }
    } 选中某一列的某一行时会调用这个方法
    - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)rowinComponent:(NSInteger)component{
    //当是第0列的时候.(省份列)
    if(component == 0){ 记录当前选中的省份的角标
    self.curProIndex = row;
    //刷新列表.
    [pickerView reloadAllComponents];
    //让第1列的第0行成为选中状态.(让城市列每次刷新时,都选中第 0个)
    [pickerView selectRow:0 inComponent:1 animated:YES];
    } //把选中的省份,城市显示到文本框当中.
    //获取选中的省.
    ProvincesItem *proItem = self.provincesDataArray[self.curProIndex];
    //获取省份的名称
    NSString *province = proItem.name;
    //获取第一列选中的行号.(城市列)
    NSInteger seleRow = [pickerView selectedRowInComponent:1];
    //获取当前选中省下选中的城市名称.
    NSString *city = proItem.cities[seleRow];
    //显示数据
    self.text = [NSString stringWithFormat:@"%@ %@",province,city];
    }

    08- 定义城市键盘(初始化文字处理)

  • 当光标点击文本框的时候,让文本框的文字为第一个自定义键盘选中的文字. 所以监听文本框架的开始编辑的代理 开始编辑时调用,(弹出键盘)became first responder

    - (void)textFieldDidBeginEditing:(UITextField *)textField{
    }
  • 在这个代理方法当中做事情.每一个文本框当中都提供一个初始化的方法.当在控制器当中调用这个初始化的方法.方法的目的就是让开始编辑选中第一列的第一行.

    - (void)initWithText;
    国旗键盘初始化方法实现:
    - (void)initWithText{
    [self pickerView:nil didSelectRow:0 inComponent:0]; }
    //日期键盘初始化方法实现:
    - (void)initWithText{
    [self dateChange:self.pick]; }
    //城市键盘初始化方法实现:
    - (void)initWithText{
    [self pickerView:self.pick didSelectRow:0 inComponent:0];
    }

    把方法的参数改成国旗,或者日期,或者城市的类型,改的一个目的是让它能够找到 initWithText 法. 传进来的参数真实类型是什么类型,它就会去调用它真实类型的方法. 如果传进来的键盘类型为日期键盘,它就会调日期的初始化方法.如果真实类型为城市,它就会去调用城市的初始化方法.

    - (void)textFieldDidBeginEditing:( FlagField *)textField{ 会去找它真实类型的方法
    [textField initWithText];
    }

    还有一个方法就是在UITextFiled的分类中声明 initWithText 方法,那么在方法 - (void)textFieldDidBeginEditing:( UITextField *)textField{ [textField initWithText]; }

  • UIPickView 和 UIDatePicker
  • 补充点:类的加载过程
  • UIPickView 和 UIDatePicker
  • 1)在加载类的load方法时,系统会先加载控制器,然后是子类,再是分类,最后才是父类
  • 2)在加载类的initialize方法时,系统会先加载控制器,然后是父类,再是分类,最后是子类.