美文网首页iOS开发进阶程序员iOS Developer
FJTimeSelectorView(刻度选择器) 介绍

FJTimeSelectorView(刻度选择器) 介绍

作者: 果哥爸 | 来源:发表于2017-12-17 17:38 被阅读23次

    之前项目中需要实现这样一个功能,效果如图所示:

    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];
            }
        }
    }
    

    四. 写在最后

    美好.jpg

    gitHub 链接:FJTimeSelectorView

    大家有兴趣可以看一下,如果觉得不错,麻烦给个喜欢或star,若发现问题或是其他好的想法请及时告知,谢谢!

    相关文章

      网友评论

        本文标题:FJTimeSelectorView(刻度选择器) 介绍

        本文链接:https://www.haomeiwen.com/subject/latuwxtx.html