之前项目中需要实现这样一个功能,效果如图所示:
FJTimeSelectorView.gif这是一个出生年月的时间选择器,当时看到这个需求第一反应就是想看下有没有好用的第三方,但是没找到因此就自己写了一个,然后封装了下,希望能帮到需要的人。
gitHub 链接:FJTimeSelectorView
集成方法:
静态:手动将
FJTimeSelectorView
文件夹拖入到工程中。
动态:CocoaPods:pod 'FJTimeSelectorView'
一.使用方法:
先生成FJTimeSelectorView
,然后设置timeScaleStyle
属性。
// timeSelectorView
- (FJTimeSelectorView *)timeSelectorView {
if(!_timeSelectorView){
CGFloat timeSelectorViewX = 12.0f;
CGFloat timeSelectorWidth = self.view.frame.size.width - 2 * timeSelectorViewX;
_timeSelectorView = [[FJTimeSelectorView alloc] initWithFrame:CGRectMake(timeSelectorViewX, CGRectGetMaxY(self.setChildrenAgeView.frame) + 20, timeSelectorWidth, 60)];
_timeSelectorView.timeScaleStyle = [[FJTimeScaleStyle alloc] init];
}
return _timeSelectorView;
}
具体参数可以通过FJTimeScaleStyle类配置:
// 刻度线 正常 高度
@property (nonatomic, assign) CGFloat timeScaleLineNormalHeight;
// 刻度线 最大 高度
@property (nonatomic, assign) CGFloat timeScaleLineMaxHeight;
// 刻度cell size
@property (nonatomic, assign) CGSize timeScaleItemSize;
// 刻度线 数量
@property (nonatomic, assign) NSInteger timeScaleCount;
// 刻度线 宽度
@property (nonatomic, assign) CGFloat timeScaleLineWidth;
// 刻度单位 (一刻度代表多少值)
@property (nonatomic, assign) NSInteger timeScaleUnit;
// 刻度线 开始 值
@property (nonatomic, assign) NSInteger timeScaleStartValue;
// 刻度线 结束 值
@property (nonatomic, assign) NSInteger timeScaleEndValue;
// 刻度线 默认值
@property (nonatomic, assign) NSInteger timeScaleDefaultValue;
// 刻度线 颜色
@property (nonatomic, strong) UIColor *timeScaleLineColor;
// 刻度 label 字体 颜色
@property (nonatomic, strong) UIColor *timeScaleLabelTextColor;
// 刻度 label 字体 大小
@property (nonatomic, strong) UIFont *timeScaleLabelFont;
// collectionView 边框 宽度
@property (nonatomic, assign) CGFloat collectionViewBorderWidth;
// collectionView 边框 颜色
@property (nonatomic, strong) UIColor *collectionViewBorderColor;
// indicatorLineWidth
@property (nonatomic, assign) CGFloat indicatorViewLineWidth;
// indicatorLayerWidth
@property (nonatomic, assign) CGFloat indicatorViewLayerWidth;
// indicatorLayerHeight
@property (nonatomic, assign) CGFloat indicatorViewLayerHeight;
// indicatorHeaderHeight
@property (nonatomic, assign) CGFloat indicatorViewHeaderHeight;
// 指示器 颜色
@property (nonatomic, strong) UIColor *indicatorViewBackgroundColor;
二.需求和思路
需求:
-
滚动时间选择器,进行时间的选取,当选择器停止滚动的时候,自动移动到最近时间点上。
-
年份必须是当前年份的前
20
年,因为孩子的年龄不能超过20
岁。 -
当滚动月份的选择器,要根据当前年份和月份算出这个月的天数,然后来自适应天数选择器。
比如当你选择2007年01月
,日期选择器定位在31日
这里,然后你滚动月份选择器到2007年02月
,这是日期选择器要自动更新,且定位在28日
这里。
- 可以设置默认选中时间
思路:
-
用
UICollectionView
做时间选择器,用CAShapeLayer
来做时间指示器,通过FJTimeScaleStyle
来进行相关参数的配置,FJTimeScaleCell
根据FJTimeScaleStyle
的相关参数进行刻度线绘制和刻度值显示。 -
通过
scrollView
代理方法来控制选择器停止滚动时,自动移动到距离最近的刻度值上。 -
通过
FJTimeScaleStyle
的设置方法来动态更新当前的选择器的刻度线和刻度值。
三. 实现难点
-
FJTimeScaleCell
宽度 计算
比如一个月有31天
,每个cell
显示5天
,这样就需要6个cell
,最后一个cell
只显示1天
且只能有1天
的刻度值宽度。
同时为了保证能够使得时间指示器可以刚好定位在刻度值的最左边和最右边,第一个cell
和最后一个cell
的宽度必须是当前时间选择器的一半。
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGFloat tmpWidth = self.tagItemSize.width;
if (indexPath.row == 0 || indexPath.row == _cellNum + 1) {
tmpWidth = self.frame.size.width / 2.0;
}
else {
NSInteger currentIndex = _timeScaleStyle.timeScaleStartValue + (indexPath.row * _timeScaleStyle.timeScaleCount * _timeScaleStyle.timeScaleUnit);
CGFloat timeSacleSpacing = self.tagItemSize.width / self.timeScaleStyle.timeScaleCount;
if (currentIndex > self.timeScaleStyle.timeScaleEndValue) {
tmpWidth = (self.timeScaleStyle.timeScaleCount - (currentIndex - self.timeScaleStyle.timeScaleEndValue)) * timeSacleSpacing;
}
}
return CGSizeMake(tmpWidth, self.tagItemSize.height);
}
- 当选择器停止滚动或是停止拖动,自动移动到距离最近的刻度值上
#pragma mark --- UIScrollView Delegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self alignCenterIndicatorViewWithScrollView:scrollView];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (decelerate == NO) {
[self alignCenterIndicatorViewWithScrollView:scrollView];
}
}
- (void)alignCenterIndicatorViewWithScrollView:(UIScrollView *)scrollView {
CGFloat timeSacleSpacing = self.tagItemSize.width / self.timeScaleStyle.timeScaleCount;
NSInteger tmpIndex = (NSInteger)roundf(scrollView.contentOffset.x / timeSacleSpacing);
CGFloat tmpContentOffsetX = timeSacleSpacing*tmpIndex;
[scrollView setContentOffset: CGPointMake(tmpContentOffsetX, 0) animated:YES];
NSInteger currentValue = self.timeScaleStyle.timeScaleStartValue + tmpIndex;
if (self.delegate && [self.delegate respondsToSelector:@selector(timeSelectorView:currentVuale:)]) {
[self.delegate timeSelectorView:self currentVuale:currentValue];
}
}
-
FJTimeScaleCell
刻度位置的计算
// 计算 位置
- (void)calculateDataModel {
CGFloat timeSacleSpacing = _timeScaleStyle.timeScaleItemSize.width / self.timeSacleCount;
[self.dataSources removeAllObjects];
for (int index = 0; index < self.timeSacleCount + 1; index++) {
NSInteger currentIndex = _timeScaleStyle.timeScaleStartValue + ((_indexPath.row - 1) * _timeScaleStyle.timeScaleCount * _timeScaleStyle.timeScaleUnit) + index;
if (currentIndex <= _timeScaleStyle.timeScaleEndValue) {
FJTimeScaleModel *model = [[FJTimeScaleModel alloc] init];
model.movePoint = CGPointMake(index * timeSacleSpacing, self.frame.size.height);
// 第一个cell 的 第一个 刻度线
if(index == 0 && self.indexPath.row == 1) {
model.addPoint = CGPointMake(index * timeSacleSpacing, self.frame.size.height - self.timeScaleMaxHeight);
}
// 每个cell 最后一个 刻度线
else if (index == self.timeSacleCount) {
model.addPoint = CGPointMake(index * timeSacleSpacing, self.frame.size.height - self.timeScaleMaxHeight);
}
else {
model.addPoint = CGPointMake(index * timeSacleSpacing, self.frame.size.height - self.timeScaleHeight);
}
[self.dataSources addObject:model];
}
}
}
四. 写在最后
美好.jpggitHub 链接:FJTimeSelectorView
大家有兴趣可以看一下,如果觉得不错,麻烦给个喜欢或star,若发现问题或是其他好的想法请及时告知,谢谢!
网友评论