UIPickerView的主要方法和城市选择器的修正

UIPickerView只有两个数据源方法.要想完整地显示出PickerView,需要结合使用代理方法 数据源方法:

// 一共有多少组(列)
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView

// 每列有多少行,传入的参数component是对应的列
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

UIPickerView的代理方法:

// 告诉系统每一行显示什么数据  通常可以结合switch case使用的
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component; 

// 监听pickerView的点击事件
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;

一些其他的常用方法

// pickerView的对象方法,选择指定列的指定行
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated

// 对象方法,获取指定列的当前选择的行的行号,如果没有选中任何行 就会返回-1
- (NSInteger)selectedRowInComponent:(NSInteger)component;

城市选择程序中同时修改省份和城市的时候,会造成程序崩溃的原因和修改方案:

在 这个项目中最容易出问题的地方是:每次选择器在变化的过程中,注意是变化的过程中,会不断地调用下面两个方法
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component

在这两个方法中,若是用这个方法以下方法获取当前被选中的项

- (NSInteger)selectedRowInComponent:
这个方法返回的的值是变化的,因此若根据这个值计算com1的选中项的索引,很容易造成数组越界。
因此我的解决方案是用成员变量这个值。每次didSelected时,也就是已经确定值之后,改变这个固定的值。

1.首先增加类的成员属性selectedRowOfComp1

2.在计算第二列也就是"城市"列的列数的时候按照成员属性存储的选择的第一行进行计算。在pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

if (component == 0) {
    return self.provinces.count;
}
MKProvince *p = self.provinces[self.selectedRowOfComp1];
return p.cities.count;

由此每行需要显示数据的方法中也做了改动:

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    if (component == 0) {
        MKProvince *p = self.provinces[row];
        return p.name;
    } else {
        MKProvince *p = self.provinces[self.selectedRowOfComp1];
        return p.cities[row];
    }
}

3.当省份部分的数据选定之后,要修改成员属性,并且刷新城市部分的数据。在label中要显示的城市和省份也是根据成员属性值来计算的:

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    if (component == 0) {
        MKProvince *p = self.provinces[row];
        // 改变lbl的显示
        self.lblProvince.text = p.name;

        // 改变城市组的显示
        self.selectedRowOfComp1 = row;
        [pickerView reloadComponent:1]; // 这句话一定要在self.selectedRowOfComp1 = row;之后。  reloadComponent:1重新加载component1但是不会改变已经选中的行号,因此可能会造成已经选中的是第二行,对于省份变成重庆这样的只有一个市的省份可能会引起bug,但是不会的,因为像这样的情况reload会将城市的数据显示为第一行
        // 更新lblCity的数据
        NSInteger cityIndex = [pickerView selectedRowInComponent:1];
        self.lblCity.text = p.cities[cityIndex];// 上一句使得component1更新,这句保证了lbl和component1数据一致
    } else {
        MKProvince *p = self.provinces[self.selectedRowOfComp1];
        // 改变lbl的显示
        self.lblCity.text = p.cities[row];
    }
}

UIDatePicker的使用,并抽取为工具类

创建一个UIDatePicker

// 先创建dataPicker
CGFloat width = [UIScreen mainScreen].bounds.size.width;
UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, width, 180)];
datePicker.locale = [NSLocale localeWithLocaleIdentifier:@"zh-Hans"]; // 设置默认的地区
datePicker.datePickerMode = UIDatePickerModeDate; // 设置输入的模式是日期
self.datePicker = datePicker; // 设置为控制器的属性
self.txtTime.inputView = self.datePicker; // 将datePicker设置为textField控件的输入器

// DatePicker输入器的附属view
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, width, 44)];
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithTitle:@"上一个" style:UIBarButtonItemStylePlain target:self action:@selector(previous)];
UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:@"下一个" style:UIBarButtonItemStylePlain target:self action:@selector(next)];
UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *item4 = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(done)]; // 设置完成的监听事件

toolbar.items = @[item1, item2, item3, item4]; 

self.txtTime.inputAccessoryView = toolbar; // 将toolbar设置为textField的输入器附属view

处理输入完成后done按钮的点击事件

- (void)done{
    [self.view endEditing:YES];
    // 将选择的日期格式化
    NSDate *date = self.datePicker.date;
    NSDateFormatter *fmt = [[NSDateFormatter alloc]init];
    fmt.dateFormat = @"yyyy年MM月dd日";
    NSString *dateStr = [fmt stringFromDate:date];
    // 将格式化后的字符串赋值给textField
    self.txtTime.text = dateStr;
}

抽取为工具类

创建工具类MKToolDatePicker,在MKToolDatePicker.h中

#import "MKTool.h"

@class UITextField;

@protocol MKToolDatePickerDelegate;
/**
 *  创建后需要强引用这个类
 */
@interface MKToolDatePicker : MKTool
/**
 *  指定要设置的UITextField控件
 */
@property (nonatomic, weak) id delegate;
- (void)datePickerOnTextField:(UITextField *)textField;
@end

@protocol MKToolDatePickerDelegate
/**
 *  当点击了时间选择器的"完成"按钮,并且代理类(一般为控制器)已经实现了该方法的时候调用,用于处理选择的NSDate
 *
 *  @param toolDatePicker 工具类对象本本身
 *  @param textField      指定的textField
 *  @param date           点击"完成"之前选择的date
 */
- (void)toolDatePicker:(MKToolDatePicker *)toolDatePicker onView:(UITextField *)textField didClickedDoneWithDate:(NSDate *)date;
@end

在MKToolDatePicker.m中

#import "MKToolDatePicker.h"
#import <UIKit/UIDatePicker.h>
#import <UIKit/UIScreen.h>
#import <UIKit/UIToolbar.h>

@interface MKToolDatePicker ()
@property (nonatomic, strong) UIDatePicker *datePicker;
@property (nonatomic, strong) UIToolbar *toolBar;
@property (nonatomic, weak) UITextField *textField;
@end
@implementation MKToolDatePicker

- (UIDatePicker *)datePicker{
    if (!_datePicker) {

        // 先创建dataPicker
        CGFloat width = [UIScreen mainScreen].bounds.size.width;
        _datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, width, 180)];
        _datePicker.locale = [NSLocale localeWithLocaleIdentifier:@"zh-Hans"];
        _datePicker.datePickerMode = UIDatePickerModeDate;
    }
    return _datePicker;
}
- (UIToolbar *)toolBar{
    if (!_toolBar) {
        // 输入的附属view
        _toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
        UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithTitle:@"上一个" style:UIBarButtonItemStylePlain target:self action:@selector(previous)];
        UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:@"下一个" style:UIBarButtonItemStylePlain target:self action:@selector(next)];
        UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
        UIBarButtonItem *item4 = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(done)];
        _toolBar.items = @[item1, item2, item3, item4];
    }
    return _toolBar;
}
- (void)datePickerOnTextField:(UITextField *)textField{
    self.textField = textField;
    textField.inputView = self.datePicker;

    textField.inputAccessoryView = self.toolBar;
}
- (void)done{
    [self.textField endEditing:YES];
    if ([self.delegate respondsToSelector:@selector(toolDatePicker:onView:didClickedDoneWithDate:)]) {
        [self.delegate toolDatePicker:self onView:self.textField didClickedDoneWithDate:self.datePicker.date];
    }
}

在控制器中使用时间选择器工具类

#import "ViewController.h"
#import "MKToolDatePicker.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *txtTime;
// 强引用时间选择器工具
@property (nonatomic, strong) MKToolDatePicker *toolDatePicker;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    MKToolDatePicker *tool = [[MKToolDatePicker alloc]init];
    self.toolDatePicker = tool;
    tool.delegate = self; // 设置代理
    [tool datePickerOnTextField:self.txtTime]; // 指定UITextView
}
// 根据onView的不同分别处理
- (void)toolDatePicker:(MKToolDatePicker *)toolDatePicker onView:(UITextField *)textField didClickedDoneWithDate:(NSDate *)date{
    NSDateFormatter *fmt = [[NSDateFormatter alloc]init];
    fmt.dateFormat = @"yyyy年MM月dd日";
    NSString *dateStr = [fmt stringFromDate:date];
    self.txtTime.text = dateStr;
}
@end

UI--UIPickerView和UIDatePicker的总结的更多相关文章

  1. Objective-c——UI进阶开发第一天(UIPickerView和UIDatePicker)

    一.知识点 1.介绍数据选择控件UIPickerView和日期选择控件UIDatePicker控件 * UIPickerView的案例 * 点餐系统 * 城市选择 * 国旗选择 * UIDatePic ...

  2. iOS学习之自定义弹出UIPickerView或UIDatePicker(动画效果)

    前面iOS学习之UIPickerView控件的简单使用 用到的UIPickerView弹出来是通过 textField.inputView = selectPicker;   textField.in ...

  3. iOs基础篇(二十二)—— UIPickerView、UIDatePicker控件的使用

    一.UIPickerView UIPickerView是一个选择器控件,可以生成单列的选择器,也可生成多列的选择器,而且开发者完全可以自定义选择项的外观,因此用法非常灵活. 1.常用属性 (1)num ...

  4. 【iOS发展-70】点菜系统案例:使用文本框inputView和inputAccessoryView串联UIPickerView、UIDatePicker和UIToolBar

    (1)效果 (2)先在storyboard中设计界面,然后源码(直接在ViewController中码) #import "ViewController.h" @interface ...

  5. IOS的UIPickerView 和UIDatePicker

    1.UIPickerView的常见属性 //数据源(用来告诉UIPickerView有多少列多少行) @property(nonatomic,assign) id<UIPikerViewData ...

  6. iOS边练边学--UIPickerView和UIDatePicker的简单使用

    一.点菜系统练习(UIPickerView) <1>UIPickerView的常用代理方法介绍 #pragma mark - <UIPickerViewDelegate> // ...

  7. iOS开发——高级UI之OC篇&UIdatePicker&UIPickerView简单使用

    UIdatePicker&UIPickerView简单使用 /***************************************************************** ...

  8. iOS中的UI

    • 不管你是学习android开发还是iOS开发• 都建议先学习UI,原因如下:UI是app的根基:⼀一个app应该是先有UI界⾯面,然后在UI的基础上增加实⽤用功能 UI相对简单易学:UI普遍是学 ...

  9. 关于 UIDatePicker 在iOS9 系统上的一个坑

    在使用 UIDatePicker时,在iOS9系统上上遇到一个很奇怪的问题,在其他系统版本中没发现,设置年月日格式显示的视图,在iOS9设备上出现中间月份无法显示的问题: 检查代码没问题,这个视图是使 ...

  10. iOS SDK Release Notes for iOS 9 iOS9 SDK 版本更新说明

    Important: This is a preliminary document for an API or technology in development. Apple is supplyin ...

随机推荐

  1. [nosql之缓存memcache]安装篇LInux for Windows

    首先呢在PHP开发的过程中会用到很多缓存服务,从而提升访问质量或者临时存储一些数据. 优点 结构简单,读取速度快,易于维护.还有一些特性memcache redis mongodb都可以用来做为缓存用 ...

  2. Linux文件(区域)锁函数 -- open()、fcntl()

    一.什么是文件锁定 对于锁这个字,大家一定不会陌生,因为我们生活中就存在着大量的锁,它们各个方面发挥着它的作用,现在世界中的锁的功能都可归结为一句话,就是阻止某些人做某些事,例如,门锁就是阻止除了屋主 ...

  3. javascript数据结构-介绍

    github博客地址 名词解释 数据结构是计算机存储.组织数据的方式.数据结构是指相互之间存在一种或多种特定关系的数据元素的集合.通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率.数据结构 ...

  4. OpenVpn简单架设

    首先Wget wget http://swupdate.openvpn.org/as/openvpn-as-2.0.24-CentOS6.i386.rpm wget http://swupdate.o ...

  5. FileZillaFTP使用教程

    FileZillaServer.exe服务启动和关闭程序 FileZilla Server Interface.exe 服务 管理程序 配置ftp服务器的用户名,密码,目录,目录读写权限 启动File ...

  6. Java JVM类加载机制

    虚拟机的类加载机制是:JVM把描述类的数据从.class文件加载到内存,并对数据进行校验.解析.初始化,最终形成可以被JVM直接使用的Java类型. 加载.连接(验证.准备.解析).初始化.使用.卸载 ...

  7. C++ 判断字符串是否全是数字

    在实际的工作中,需要提取程序中的字符串信息,但是程序中经常将一些数字当做字符串来进行处理,例如表盘的刻度信息,这时候就需要判断字符串是否全为数字,来进行真正意义上的字符串提取.下面介绍了判断字符串是否 ...

  8. 模仿mybatis,用jdk proxy实现接口

    在mybatis中,我们都只需要定义一个mapper接口,但并不需要对它进行任务实现.只要有对就的mapper.xml文件就可以访问数据库.那么,没有接口的访问是如何实现的呢. 答案就是JDK pro ...

  9. [转]odoo常用openerp-server.conf配置参数详解

    参数 说明 用法 addons_path addons模块的查找路径,多个路径用逗号分隔 addons_path = E:\GreenOdoo8.0\source\openerp\addons csv ...

  10. UTC与GMT时间

    整个地球分为二十四时区,每个时区都有自己的本地时间.在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC, Universal Time Coordinated).UTC与格 ...