自定义iOS选择器 附农历选择器代码

移动开发 iOS
本文为cocoachina的会员自定义的 iOS 自带的滚轮选择器,这里分享了开发的经验和实现源码,希望给大家一些帮助。

1.鉴于模拟器和真机的滚动效果的差异,建议大家真机调试的时候注释掉IDJScrollComponent.m里的如下内容:

  1. self.decelerationRate=0

2.我的代码中使用了iOS5.0的UIImage的缩放图片的resizableImageWithCapInsets:方法,如果你使用的是iOS5.0以下的SDK,请替换为stretchableImageWithLeftCapWidth:topCapHeight:方法。

3.几处BUG:

(1.)copy的我忘记释放内存了。

  1. NSString *pYear=[cal.year copy]; 
  2. NSString *pMonth=[cal.month copy]; 

这个pYear, pMonth没释放!

(2.)UITableViewCell的释放有些问题。

cellForRowAtIndexPath方法里面, cell的初始化有以下三种情况,

  1. cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
  2. cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
  3. cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; 

假设是调用这句 cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 初始化

然后最后return [cell autorelease]; 就有问题了!

这样改, 把另外2种初始化改成

  1. cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
  2. cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; 

然后最后return cell;就OK了。

(3.)算法的局限性。

IDJScrollComponent.m里的moveSubViews:方法由于算法欠妥,导致了一个局限性,就是滚轮图片的高度必须是可以被显示的行数整除的数字,譬如:我的例子日期显示三行,那么滚轮的图片高度就是177像素的,177恰好可以被3整除。

(4.)农历数据提供器IDJChineseCalendar.mm的- (id)initWithYearStart:(NSUInteger)start end:(NSUInteger)end:方法:

  1. //获取当年的公历年份对应的农历的年代和甲子年份 
  2. std::pair p=ChineseCalendarDB::GetEraAndYearOfLunar([self.year intValue]); 

需要移动到

  1. //设置当前时间的农历日期字段 
  2. self.year=[NSString stringWithFormat:@"%d", chineseDate.GetYear()]; 

的后面。

这个控件并不是对iOS自带的UIPickerView贴图,而是重新实现,我一周多的成果,期间走了不少弯路。哈!

此控件开发的原因:

最近有个需求,需要做一个农历的日期滚轮选择器,一开始想用iOS自带的UIPickerView,但是设计人员要求的比较高,必须实现她要求的样式,也就是上图中大家看到的样式。但是UIPickerView根本没有提供可以定制样式(也就是更换皮肤)的接口。首先我在论坛上找到了帖子,按照这位兄台所述,确实可以在一定程度上修改UIPickerView的图片,我之所以说一定程度上,有以下几个原因:

(1.)他是用覆盖原有的UIPickerView上的各个子视图上图片的方法做的,那么你提供新的图片就必须与原图片严丝合缝。这也说明,即便是图片换了,样式也是不能换的,譬如:分割线的粗细、上下左右的边框的大小等,也就是不能完全DIY,不能满足我的需求。

(2.)由于覆盖UIPickerView上的各个子视图上图片的做法不是苹果官方给出的,一旦以后某个版本的UIPickerView实现策略改变,例如:3号子视图不再是滚轮的背景图片,你的做法就挂了。

于是我就实现了上图中的滚轮选择器,它与UIPickerView的区别是:

(1.)皮肤图片提供了方法可以做替换的。

(2.)可以选择滚轮上的数据是否循环滚动。

(3.)可以指定选择条的位置。

为了代码的复用,也就是所谓的OOP,我按照以下的方式实现(因为我觉得这个滚轮选择器的实现方案其实算不上亮点,因为有很多的方案可以选择的,但是程序的结构、代码的重用是很重要的):

(1.)pickerview目录:这个目录中的IDJPickerView.h是滚轮选择器视图,没有任何和与数据相关的东西,也就是你可以在IDJPickerView上显示任何数据。IDJPickerView通过委托获取需要显示的数据。这个目录下的IDJScrollComponent.h实现了UIScrollView上的内容可以反复循环滚动的功能。

(2.)datepicker目录:IDJDatePickerView.h实现了IDJPickerView里的协议,并把IDJPickerView做为自己的一个私有成员,实现了一个可以根据type字段显示公历、农历的日期选择器,IDJDatePickerView.m里的农历算法用的是solar_chinese_calendar目录中的C++算法,因此农历的相关数据类使用了C++混编的代码。其实iOS自己支持农历的,但是存在BUG,具体的原因大家可以看我的IDJChineseCalendar.mm的源码,里面的注释比较详细的。我在这里也使用了一层封装,也就是IDJDatePickerView.m本身也不提供数据,而是通过IDJCalendar.h、IDJChineseCalendar.h、IDJCalendarUtil.h来提供,这样既实现了数据与视图的分离(因为农历算法太复杂了,直接写在IDJDatePickerView.m里会使得代码看起来可读性太差了),而且把C++的调用封装在了数据层,使得IDJDatePickerView.m的视图层代码不会出现C++的API。

(3.)timepicker目录:这个目录纯粹是一个Demo,展示了一个不循环滚动、显示行数与选中条位置不对称的选择器,没有什么实际的含义。

一开始我是纯粹写农历的选择器,代码都是耦合在一起的,后来逐个拆开的,这样代码就可以复用了,不仅仅是农历选择器,而是可以承载任何数据。

责任编辑:佚名 来源: cocoachina
相关推荐

2017-03-20 14:46:07

Android日期时间选择器

2012-12-27 14:08:39

Android开发颜色选择器

2011-11-28 13:42:55

Sencha Touc组件选择器

2010-09-03 09:30:29

CSS选择器

2010-09-07 11:14:32

CSS属性选择器CSS

2009-07-16 11:02:33

Swing文件选择器

2013-03-11 10:30:56

CSSWeb

2022-05-10 07:49:40

CSS选择器

2023-03-16 10:20:55

CSS选择器

2010-07-20 10:11:32

jQuery选择器Sizzle

2010-12-27 16:01:45

jQuery选择器

2010-09-06 08:52:00

CSS选择器

2010-08-26 12:47:15

CSSclass

2023-01-30 08:42:33

CSS选择器性能

2016-10-25 14:49:49

javascriptmaterial-uidatepicker

2020-10-25 08:57:56

CSS前端浏览器

2012-06-12 09:43:11

jQuery

2011-10-24 10:30:20

CSS

2011-07-22 17:52:46

iPhone 时间 控件

2017-10-25 14:07:54

APPiOSxcode
点赞
收藏

51CTO技术栈公众号