iOS仿刻度尺demo

作者: 丸_子 | 来源:发表于2017-01-19 17:18 被阅读1550次

    效果:

    1.png

    .h文件

    //
    //  SXSRulerControl.h
    //  SXSInvestScaleSlider
    //
    //  Created by Angela on 16/9/26.
    //  Copyright © 2016年 iaiai. All rights reserved.
    //
    
    #import
    
    IB_DESIGNABLE  //轻量级标尺控件
    
    @interface SXSRulerControl : UIControl
    
    @property (nonatomic, assign) IBInspectable CGFloat selectedValue;//选中的数值
    
    @property (nonatomic, assign) IBInspectable NSInteger minValue;//最小值
    
    @property (nonatomic, assign) IBInspectable NSInteger maxValue;//最大值
    
    @property (nonatomic, assign) IBInspectable NSInteger valueStep;//步长
    
    @property (nonatomic, assign) IBInspectable CGFloat minorScaleSpacing;//小刻度间距,默认值 `8.0`
    
    @property (nonatomic, assign) IBInspectable CGFloat majorScaleLength;//主刻度长度,默认值 `40.0`
    
    @property (nonatomic, assign) IBInspectable CGFloat middleScaleLength;//中间刻度长度,默认值 `25.0`
    
    @property (nonatomic, assign) IBInspectable CGFloat minorScaleLength;//小刻度长度,默认值 `10.0`
    
    @property (nonatomic, strong) IBInspectable UIColor *rulerBackgroundColor;//刻度尺背景颜色,默认为 `clearColor`
    
    @property (nonatomic, strong) IBInspectable UIColor *scaleColor;//刻度颜色,默认为 `lightGrayColor`
    
    @property (nonatomic, strong) IBInspectable UIColor *scaleFontColor;// 刻度字体颜色,默认为 `darkGrayColor`
    
    @property (nonatomic, assign) IBInspectable CGFloat scaleFontSize;//刻度字体尺寸,默认为 `10.0`
    
    @property (nonatomic, strong) IBInspectable UIColor *indicatorColor;//指示器颜色,默认 `redColor`
    
    @property (nonatomic, assign) IBInspectable CGFloat indicatorLength;//指示器长度,默认值为 `40.0`
    
    @property (nonatomic, assign) IBInspectable NSInteger midCount;//几个大格标记一个刻度
    
    @property (nonatomic, assign) IBInspectable NSInteger smallCount;//一个大格里面几个小格
    
    @end
    

    .m文件

    //
    //  SXSRulerControl.m
    //  SXSInvestScaleSlider
    //
    //  Created by iaiai on 16/9/26.
    //  Copyright © 2016年 iaiai. All rights reserved.
    //
    
    #import "SXSRulerControl.h"
    #define kMinorScaleDefaultSpacing   20    // 小刻度间距
    #define kMajorScaleDefaultLength    25.0  //主刻度高度
    #define kMiddleScaleDefaultLength   17.0  //中间刻度高度
    #define kMinorScaleDefaultLength    10.0  //小刻度高度
    #define kRulerDefaultBackgroundColor    ([UIColor clearColor])  //刻度尺背景颜色
    #define kScaleDefaultColor          ([UIColor lightGrayColor])  //刻度颜色
    #define kScaleDefaultFontColor      ([UIColor darkGrayColor])  //刻度字体颜色
    #define kScaleDefaultFontSize       10.0  //刻度字体
    #define kIndicatorDefaultColor      ([UIColor redColor])  //指示器默认颜色
    #define kIndicatorDefaultLength     80  //指示器高度
    
    @interface SXSRulerControl ()
    
    @end
    
    @implementation SXSRulerControl{
        UIScrollView *_scrollView;
        UIImageView *_rulerImageView;
        UIView *_indicatorView;
    }
    
    #pragma mark - 构造函数
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self setupUI];
        }
        return self;
    }
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        if (_rulerImageView.image == nil) {
            [self reloadRuler];
        }
        CGSize size = self.bounds.size;
        _indicatorView.frame = CGRectMake(size.width * 0.5, size.height - self.indicatorLength, 1, self.indicatorLength);
    
        // 设置滚动视图内容间距
        CGSize textSize = [self maxValueTextSize];
        CGFloat offset = size.width * 0.5 - textSize.width;
        _scrollView.contentInset = UIEdgeInsetsMake(0, offset, 0, offset);
    }
    
    #pragma mark - 设置属性
    //指示器颜色
    - (void)setIndicatorColor:(UIColor *)indicatorColor {
        _indicatorView.backgroundColor = indicatorColor;
    }
    
    ////选中的数值
    - (void)setSelectedValue:(CGFloat)selectedValue {
        if (selectedValue <</span> _minValue || selectedValue > _maxValue || _valueStep <= 0) {
            return;
        }
    
        _selectedValue = selectedValue;
        [self sendActionsForControlEvents:UIControlEventValueChanged];
        CGFloat spacing = self.minorScaleSpacing;
        CGSize size = self.bounds.size;
        CGSize textSize = [self maxValueTextSize];
        CGFloat offset = 0;
    
        // 计算偏移量
        CGFloat steps = [self stepsWithValue:selectedValue];
        offset = size.width * 0.5 - textSize.width - steps * spacing;
        _scrollView.contentOffset = CGPointMake(-offset, 0);
    }
    
    #pragma mark - UIScrollViewDelegate
    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
        CGFloat spacing = self.minorScaleSpacing;
        CGSize size = self.bounds.size;
        CGSize textSize = [self maxValueTextSize];
        CGFloat offset = targetContentOffset->x + size.width * 0.5 - textSize.width;
        NSInteger steps = (NSInteger)(offset / spacing + 0.5);
        targetContentOffset->x = -(size.width * 0.5 - textSize.width - steps * spacing) - 0.5;
    }
    
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        if (!(scrollView.isDragging || scrollView.isTracking || scrollView.isDecelerating)) {
            return;
        }
    
        CGFloat spacing = self.minorScaleSpacing;
        CGSize size = self.bounds.size;
        CGSize textSize = [self maxValueTextSize];
        CGFloat offset = 0;
        offset = scrollView.contentOffset.x + size.width * 0.5 - textSize.width;
        NSInteger steps = (NSInteger)(offset / spacing + 0.5);
        CGFloat value = _minValue + steps * _valueStep/(_midCount*_smallCount);
    
        if (value != _selectedValue && (value >= _minValue && value <= _maxValue)) {
            _selectedValue = value;
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        }
    }
    
    #pragma mark - 绘制标尺相关方法
    - (void)reloadRuler {
        UIImage *image = [self rulerImage];
        if (image == nil) {
            return;
        }
    
        _rulerImageView.image = image;
        _rulerImageView.backgroundColor = self.rulerBackgroundColor;
        [_rulerImageView sizeToFit];
        _scrollView.contentSize = _rulerImageView.image.size;
    
        // 水平标尺靠下对齐
        CGRect rect = _rulerImageView.frame;
        rect.origin.y = _scrollView.bounds.size.height - _rulerImageView.image.size.height;
        _rulerImageView.frame = rect;
    
        // 更新初始值
        self.selectedValue = _selectedValue;
    }
    
    - (UIImage *)rulerImage {
        // 1. 常数计算
        CGFloat steps = [self stepsWithValue:_maxValue];
        if (steps == 0) {
            return nil;
        }
    
        // 水平方向绘制图像的大小
        CGSize textSize = [self maxValueTextSize];
        CGFloat height = _scrollView.frame.size.height-_rulerImageView.frame.size.height ;
        CGFloat startX = textSize.width;
        CGRect rect = CGRectMake(0, 0, steps * self.minorScaleSpacing + 2 * startX, height);
    
        // 2. 绘制图像
        UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
    
        // 1> 绘制刻度线
        UIBezierPath *path = [UIBezierPath bezierPath];
    
        for (NSInteger i = _minValue; i <= _maxValue; i += _valueStep) {
            // 绘制主刻度下
            CGFloat x = (i - _minValue) / _valueStep * self.minorScaleSpacing * (_midCount*_smallCount) + startX;
            [path moveToPoint:CGPointMake(x, height)];
            [path addLineToPoint:CGPointMake(x, height - self.majorScaleLength)];
    
            // 绘制主刻度上
            [path moveToPoint:CGPointMake(x, 0)];
            [path addLineToPoint:CGPointMake(x,self.majorScaleLength)];
            if (i == _maxValue) {
                break;
            }
    
            // 绘制小刻度线下
            for (NSInteger j = 1; j < (_midCount*_smallCount); j++) {
                CGFloat scaleX = x + j * self.minorScaleSpacing;
                [path moveToPoint:CGPointMake(scaleX, height)];
                CGFloat scaleY = height - ((j%_smallCount == 0) ? self.middleScaleLength : self.minorScaleLength);
                [path addLineToPoint:CGPointMake(scaleX, scaleY)];
            }
    
            // 绘制小刻度线上
            for (NSInteger j = 1; j < (_midCount*_smallCount); j++) {
                CGFloat scaleX = x + j * self.minorScaleSpacing;
    
                //上
                [path moveToPoint:CGPointMake(scaleX, 0)];
                CGFloat scaleY =((j%_smallCount == 0) ? self.middleScaleLength : self.minorScaleLength);
    
                //上
                [path addLineToPoint:CGPointMake(scaleX, scaleY)];
            }
        }
        [self.scaleColor set];
        [path stroke];
    
        // 2> 绘制刻度值
        NSDictionary *strAttributes = [self scaleTextAttributes];
        for (NSInteger i = _minValue; i <= _maxValue; i += _valueStep) {
            NSString *str = @(i).description;
    
            CGRect strRect = [str boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT)
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                            attributes:strAttributes
                                               context:nil];
    
            strRect.origin.x = (i - _minValue) / _valueStep * self.minorScaleSpacing *( _midCount*_smallCount) + startX - strRect.size.width * 0.5;
            strRect.origin.y =_scrollView.frame.size.height*0.5-textSize.height*0.5;
            [str drawInRect:strRect withAttributes:strAttributes];
        }
    
        UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return result;
    }
    
    - (CGFloat)stepsWithValue:(CGFloat)value {
        if (_minValue >= value || _valueStep <= 0) {
            return 0;
        }
        return (value - _minValue) / _valueStep *( _midCount*_smallCount);
    }
    
    - (CGSize)maxValueTextSize {
        NSString *scaleText = @(self.maxValue).description;
        CGSize size = [scaleText boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT)
                                              options:NSStringDrawingUsesLineFragmentOrigin
                                           attributes:[self scaleTextAttributes]
                                              context:nil].size;
    
        return CGSizeMake(floor(size.width), floor(size.height));
    }
    
    - (NSDictionary *)scaleTextAttributes {
        CGFloat fontSize = self.scaleFontSize * [UIScreen mainScreen].scale * 0.6;
    
        return @{NSForegroundColorAttributeName: self.scaleFontColor,
                 NSFontAttributeName: [UIFont boldSystemFontOfSize:fontSize]};
    }
    
    #pragma mark - 设置界面
    - (void)setupUI {
        // 滚动视图
        _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
        _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _scrollView.showsVerticalScrollIndicator = NO;
        _scrollView.showsHorizontalScrollIndicator = NO;
        _scrollView.delegate = self;
        _scrollView.layer.borderWidth=0.5;
        _scrollView.layer.borderColor=kScaleDefaultColor.CGColor;
        [self addSubview:_scrollView];
    
        // 标尺图像
        _rulerImageView = [[UIImageView alloc] init];
        [_scrollView addSubview:_rulerImageView];
        // 指示器视图
        _indicatorView = [[UIView alloc] init];
        _indicatorView.backgroundColor = self.indicatorColor;
        [self addSubview:_indicatorView];
    }
    
    #pragma mark - 属性默认值
    //小刻度间距
    - (CGFloat)minorScaleSpacing {
        if (_minorScaleSpacing <= 0) {
            _minorScaleSpacing = kMinorScaleDefaultSpacing;
        }
        return _minorScaleSpacing;
    }
    
    //主刻度长度
    - (CGFloat)majorScaleLength {
        if (_majorScaleLength <= 0) {
            _majorScaleLength = kMajorScaleDefaultLength;
        }
        return _majorScaleLength;
    }
    
    //中间刻度长度
    - (CGFloat)middleScaleLength {
        if (_middleScaleLength <= 0) {
            _middleScaleLength = kMiddleScaleDefaultLength;
        }
        return _middleScaleLength;
    }
    
    //小刻度长度
    - (CGFloat)minorScaleLength {
        if (_minorScaleLength <= 0) {
            _minorScaleLength = kMinorScaleDefaultLength;
        }
        return _minorScaleLength;
    }
    
    //刻度尺背景颜色
    - (UIColor *)rulerBackgroundColor {
        if (_rulerBackgroundColor == nil) {
            _rulerBackgroundColor = kRulerDefaultBackgroundColor;
        }
        return _rulerBackgroundColor;
    }
    
    //刻度颜色
    - (UIColor *)scaleColor {
        if (_scaleColor == nil) {
            _scaleColor = kScaleDefaultColor;
        }
        return _scaleColor;
    }
    
    // 刻度字体颜色
    - (UIColor *)scaleFontColor {
        if (_scaleFontColor == nil) {
            _scaleFontColor = kScaleDefaultFontColor;
        }
        return _scaleFontColor;
    }
    
    //刻度字体尺寸
    - (CGFloat)scaleFontSize {
        if (_scaleFontSize <= 0) {
            _scaleFontSize = kScaleDefaultFontSize;
        }
        return _scaleFontSize;
    }
    
    //指示器颜色
    - (UIColor *)indicatorColor {
        if (_indicatorView.backgroundColor == nil) {
            _indicatorView.backgroundColor = kIndicatorDefaultColor;
        }
        return _indicatorView.backgroundColor;
    }
    
    //指示器长度
    - (CGFloat)indicatorLength {
        if (_indicatorLength <= 0) {
            _indicatorLength = kIndicatorDefaultLength;
        }
        return _indicatorLength;
    }
    @end
    

    在控制器中使用:

     //
    //  SXSRulerControlVC.m
    //  SXSInvestScaleSlider
    //
    //  Created by Angela on 16/9/26.
    //  Copyright © 2016年 iaiai. All rights reserved.
    //3.8M
    #import "SXSRulerControlVC.h"
    #import "SXSRulerControl.h"
    
    @interface SXSRulerControlVC ()<</span>UITextFieldDelegate>
    
    @property (nonatomic, strong) UITextField *textfield;
    @property (nonatomic, strong) SXSRulerControl *ruler;
    
    @end
    
    @implementation SXSRulerControlVC
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        _textfield=[[UITextField alloc]initWithFrame:CGRectMake(80, 100, 100, 40)];
        _textfield.backgroundColor=[UIColor lightGrayColor];
        _textfield.textAlignment=NSTextAlignmentCenter;
        _textfield.delegate=self;
    
        [self.view addSubview:_textfield];
        _ruler = [[SXSRulerControl alloc] initWithFrame:CGRectMake(20, 0,[UIScreen mainScreen].bounds.size.width-40, 80)];
        _ruler.center = self.view.center;
        [self.view addSubview:_ruler];
        _ruler.backgroundColor = [UIColor colorWithWhite:0.93 alpha:1];
        _ruler.midCount=2;//几个大格标记一个刻度
        _ruler.smallCount=5;//一个大格几个小格
        _ruler.minValue = 0;// 最小值
        _ruler.maxValue = 3000;// 最大值
        _ruler.valueStep = 400;// 两个标记刻度之间相差大小
    
        //每个小格格大值计算为:ruler.valueStep÷(ruler.midCount*ruler.smallCount)
        _ruler.selectedValue = 1000;// 设置默认值
        [_ruler addTarget:self action:@selector(selectedValueChanged:) forControlEvents:UIControlEventValueChanged]; // 添加监听方法
    }
    
    - (void)selectedValueChanged:(SXSRulerControl *)ruler {
        _textfield.text = [NSString stringWithFormat:@"%.f", ruler.selectedValue];
    }
    
    -(void)textFieldDidEndEditing:(UITextField *)textField{
        _ruler.selectedValue=textField.text.integerValue;
    }
    
    -(void)textFieldDidBeginEditing:(UITextField *)textField{
        _ruler.selectedValue=textField.text.integerValue;
    }
    @end
    

    相关文章

      网友评论

      本文标题:iOS仿刻度尺demo

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