iOS仿刻度尺demo

效果:

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,456评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,763评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,265评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,716评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,071评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,435评论 1 212
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,751评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,437评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,148评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,411评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,912评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,281评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,913评论 3 234
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,020评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,776评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,462评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,350评论 2 262

推荐阅读更多精彩内容