iOS自定义游标滑尺

来源:互联网 发布:js隐藏显示tr 编辑:程序博客网 时间:2024/05/17 02:59

前言

由于公司项目需要,现在需要制作一个游标滑尺来让用户选择金额与时间。查找了大量的资料和相关代码,再次完成后记录下来。

内容

需求

  1. 需求是尺子不动,用户可以通过游标进行滑动选择
  2. 滑动的时候可以动态获取当前游标指示的数值
  3. 滑动结束后,游标会自动靠近临近的刻度尺,保证选择的是刻度尺上的值
  4. 附带一个开关,当开关打开的时候游标依然可以滑动,但是选择值的时候只能选择最大值或者最小值中的一个,游标在选择结束的时候进行判定并移动到最大或最小的位置

实现过程

  1. 首先拿到需求后,考虑刻度尺的实现,实现方式无非两种,一种是图片一种是drawRect方法里面自己画,因为考虑到广泛引用这点,所以决定在drawRect方法中自己绘制,因此画刻度尺的关键代码如下:
//添加底线    CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);//设置线的颜色,默认是黑色    CGPoint points[2];    points[0] = CGPointMake(_marginLeft, rect.size.height-1);    points[1] = CGPointMake(_marginLeft+_widthOfItem*_numberOfItem, rect.size.height-1);    CGContextAddLines(context, points, 2);    _lineViewRect = CGRectMake(_marginLeft-2, rect.origin.y, _widthOfItem*_numberOfItem+4, rect.size.height);    //画刻度    for (int i = 0; i <= _numberOfItem; i ++){        //移动画笔的位置        CGContextMoveToPoint(context, _marginLeft+_widthOfItem*i, rect.size.height);        //当是组的数值的时候需要画长线同时画数字        if ((i*_itemValue+_minValue)%_groupValue == 0 || i == 0){            //显示的数字内容            NSString *num = [NSString stringWithFormat:@"%.ld%@",i *_itemValue +_minValue,_unit];            //如果数字上万            if ([num floatValue]>1000000){                num = [NSString stringWithFormat:@"%.f万%@",[num floatValue]/10000.f,_unit];            }            //设置字体            NSDictionary *attribute = @{NSFontAttributeName:TextRulerFont,NSForegroundColorAttributeName:XC_APP_BGCOLOR};            CGFloat width = [num boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:0 attributes:attribute context:nil].size.width;            //画数字            [num drawInRect:CGRectMake(_marginLeft+_widthOfItem*i-width/2, 0, width, 14) withAttributes:attribute];            //画标尺            CGContextAddLineToPoint(context, _marginLeft+_widthOfItem*i,rect.size.height-longLineY);        }else{            //不是组的数值的时候,画短标尺            CGContextAddLineToPoint(context, _marginLeft+_widthOfItem*i,rect.size.height - shortLineY);        }        CGContextStrokePath(context);//开始绘制    }

关于drawRect方法的调用

drawRect方法的调用是在ViewController的loadView方法和ViewDidLoad方法调用之后,所以在ViewController中依然可以给drawRect方法中需要用到的值赋值。
但是仍然要注意以下几点:
1、如果在UIView初始化时没有设置rect大小,将会直接导致drawRect不被自动调用。
2、该方法在调用sizeThatFits后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0.
以上1,2推荐;而3,4不提倡

画游标

既然已经画好了刻度尺,那么接下来的操作就是绘制游标以及对游标的控制了。

游标的绘制

游标同样我们也选择绘制出来(暂时没有考虑使用图片,有需要的同学可以自己尝试做一下),废话不多说上代码:

//画游标    CGContextSetRGBFillColor(context, 255.0f, 0.0f, 0.0f, 1.0);    CGContextSetRGBStrokeColor(context, 255.0f, 0.0f, 0.0f, 1.0);    //画游标的实心圆    CGContextAddArc(context, _currentXPosition, 15, 5, 0, 2*M_PI, 0);    CGContextDrawPath(context, kCGPathFill);    CGPoint cursorLinePoint[2];    cursorLinePoint[0] = CGPointMake(_currentXPosition, 10);    cursorLinePoint[1] = CGPointMake(_currentXPosition, rect.size.height - 1);    CGContextAddLines(context, cursorLinePoint, 2);    CGContextStrokePath(context);//开始绘制

游标的控制

既然已经有了游标,那么接下来的问题是如何控制游标而不让刻度尺发生移动,在绘制的代码中,聪明的同学应该能够看出,我在横向坐标中并没有写成固定值,意思就是说游标的控制依然是要通过不断的重新绘制实现的,所以我写了一个全局的变量来规定游标的位置,在发生拖动事件的时候改变X坐标,并且让其重新绘制游标,就达到了我们移动游标的效果。
综上所述,我在beginTrackingWithTouch方法、continueTrackingWithTouch方法以及endTrackingWithTouch方法中进行了游标的位置更改的操作,将点击事件的x坐标赋值给了游标的位置,同时限制了游标的位置,防止超出刻度尺。而考虑到我们的需求,在停止滑动的时候还需要对游标的位置进行判定,要求其落在刻度线上。在我们修改完坐标后,调用

[self setNeedsDisplay];

重新绘制游标即可。
以上关于滑动时的坐标就已经解决清楚了,但是,我们还有一个问题没有解决好,当我们完成上述处理后,会发现我们的滑动事件处理的并不完备,虽然我们处理了滑动并且也能让游标在停止滑动的时候停在刻度尺上,但是我们还有一个需求:动态获取当前游标选择的值。关于这个需求我们的处理是在ViewController中给当前控件添加UIControlEventValueChanged的事件,然后在beginTrackingWithTouch方法、continueTrackingWithTouch方法以及endTrackingWithTouch方法中添加对事件的触发

[self sendActionsForControlEvents:UIControlEventValueChanged];

这样,我们就可以在ViewController的UIControlEventValueChanged对应的事件中获得到当前控件里游标的位置了。
至此,我们这个自定义控件的需求就全部完成。效果图如下:
图片.png
下面给出源码地址:
Demo地址(CSDN)
本人学识经验尚浅,如果有什么改进意见或建议,请在下方留言,不胜感激。

阅读全文
0 0
原创粉丝点击