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- 定义国旗键盘

  • 运行例效果:

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

    • 对应的模型:

    • #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
      //加载数据
      //数据内容对应的模型图://数组当中保存的都是字典.我们看到字典就会它转成模型.
      所以新建了一个 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;
      }
    • 执行过程:

    • 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-自定义生日键盘

    运行示例效果:

    • 点击生日时弹出的是一个日期键盘. 实现这种效果采取的方案是自定义一个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
  • 加载数据

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

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

  • 所以新建了一个 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]; }

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

转载于:https://www.cnblogs.com/zhoudaquan/p/5014078.html

UIPickView 和 UIDatePicker相关推荐

  1. 这个我过滤概述UIPickerView键盘处理

    一.介绍UIPickView和UIDatePicker(了解) 1.UIPickView什么时候用? 通常在注册模块,当用户需要选择一些东西的时候,比如说城市,往往弹出一个PickerView给他们选 ...

  2. 如何弹出UIDatePicker最好

    UIDateicker并没有继承UIPickerView,它的宽度只有iphone的宽度,在ipad上直接显示出来非常不协调,所以苹果建议用UIPopoverViewController来显示,所以你 ...

  3. UIDatePicker | 时间选择器

    一:UIDatePicker的介绍 UIDatePicker 是一个控制器类,封装了 UIPickerView,但是他是UIControl的子类,专门用于接受日期.时间和持续时长的输入. 日期选取器的 ...

  4. iOS基础-UIKit框架-高级视图-UIDatePicker

    用处:用在自定义键盘(点击文本框时弹出日期选择.) 一.自定义键盘 先连接TextField -(viewDidLoad){[super viewDidLoad]; //1.创建时间选择器 UIDat ...

  5. 【IOS 开发】基本 UI 控件详解 (UIDatePicker | UIPickerView | UIStepper | UIWebView | UIToolBar )

    转载注明出处 : http://blog.csdn.net/shulianghan/article/details/50348982 一. 日期选择器 (UIDatePicker) UIDatePic ...

  6. Cocoa touch(十):UIDatePicker

    UIDatePicker,日期选取器 typedef NS_ENUM(NSInteger, UIDatePickerMode) {UIDatePickerModeTime, // Displays h ...

  7. 疯狂ios讲义疯狂连载之日期选择器(UIDatePicker)

    UIDatePicker是一个可以用来选择日期和时间的控件.除此之外,它也可作为倒计时控件. 日期选择器(UIDatePicker)继承了UIControl,因此UIDatePicker可以作为活动控 ...

  8. 利用Runtime修改UIdatePicker的字体颜色

    用过苹果原生UIdatePicker的Ios开发者都知道,UIdatePicker这个时间选择器的字体颜色默认的是黑色,并且官方API并没有提供可以修改字体颜色的API.如下: UIDatePicke ...

  9. UIDatePicker 日期/时间选取器(滚轮)—IOS开发

    UIDatePicker 是一个控制器类,封装了 UIPickerView,但是他是UIControl的子类,专门用于接受日期.时间和持续时长的输入.日期选取器的各列会按照指定的风格进行自动配置,这样 ...

最新文章

  1. jdk javac运行不了_Intellij IDEA搭建jdk源码阅读环境
  2. 20165101刘天野 2018-2019-2《网络对抗技术》第1周 Kali的安装
  3. Ceph 存储集群7-故障排除
  4. python图片比对、自动化测试,腾讯优图及知脸(ZKface)人脸比对接口测试(python)
  5. [spring]Attribute scope must be declared for element type bean
  6. 力作推荐!!!!   防线:企业Linux安全运维理念和实战(向世界500强企业学习Linux安全管理与运维之道)...
  7. 华南理工网络计算机基础知识,2019年华南理工大学网络教育计算机基础随堂练习题第一章.docx...
  8. 安装office2010出现了错误,提示要安装MSXML6.10.1129.0解决方法
  9. 支持!解决卡巴斯基程序错误及程序断开的问题!
  10. 金山词霸2007两个小BUG
  11. 常见的U盘,内存卡修复工具及其修复方法
  12. 在宿舍的同学们,只要你有本本,就可以免费无线上网~~
  13. linux 查看网口实时流速_Linux查看实时带宽流量情况
  14. CentOS搭建tg的MTProxy代理
  15. Springcloud微服务中多模块重复代码重构成公共模块的实现
  16. 小码哥CRM项目(二)p20~p35
  17. 冯成毅:各类交易者的深度心理剖析
  18. RGB图灰度及通道理解
  19. 混合动力汽车用导热电池粘合剂市场现状及未来发展趋势
  20. 使地方坐标系BIM模型与CAD严格在LSV内对准

热门文章

  1. Cocos2d-x学习之---关于CCScrollView
  2. Spring入门(四):使用Maven管理Spring项目
  3. 2.Elasticsearch插件推荐及安装
  4. java.sql.SQLException: Can not issue empty query.
  5. 消除类游戏(js版)
  6. 问题 C: 判断三角形的性质
  7. OpenCV-python学习笔记(一)——image basics输入输出,像素处理和绘制图形
  8. python管道怎么使用_python中管道用法入门实例
  9. python多继承_Python多继承,__init__
  10. java 创建存储过程_如何在pl/sql中创建及调用JAVA存储过程 | 学步园