CustomSlider

公司有这么一个需求,滑动滑竿选择项目的造价值。第一反应应该是使用UISlider了,但是设计这边给我一个设计图之后,我觉得没那么简单了。

  • 分析主要的几点
  • 滑竿跟按钮
  • 尺度
  • 标注(麻烦的地方)

初始化Slider控件

首先我把slider、标尺、标注封装成在一个继承UIControl的PriceSliderView视图中,当然这个父视图可以是UIView,可能我想以后有什么拓展,比如点击某个位置,滑标就移动到哪里,那么就要点击事件。当然这个我没有做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 在PriceSliderView的init方法中初始化控件
- (instancetype)init{
self = [super init];
if (self) {
UISlider *slider = [[UISlider alloc] init];
// 设置滑标的状态图片
[slider setThumbImage:[UIImage getImageWithName:@"publish_icon_price_chose"] forState:UIControlStateNormal];
[slider setThumbImage:[UIImage getImageWithName:@"publish_icon_price_chose"] forState:UIControlStateHighlighted];
// 设置滑杆最大值(滑标的右边)的状态图片
[slider setMaximumTrackImage:[UIImage getImageWithName:@"publish_icon_price_line"] forState:UIControlStateNormal];
[slider setMaximumTrackImage:[UIImage getImageWithName:@"publish_icon_price_line"] forState:UIControlStateHighlighted];
// 设置滑杆最小值(滑标的左边)的状态图片
[slider setMinimumTrackImage:[UIImage getImageWithName:@"publish_icon_price_line"] forState:UIControlStateNormal];
[slider setMinimumTrackImage:[UIImage getImageWithName:@"publish_icon_price_line"] forState:UIControlStateHighlighted];
// 添加方法监听值得变化
[slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
// 根据需求设置滑杆最大、最大值
// 因为需求分成7个分段
[slider setMinimumValue:0];
[slider setMaximumValue:7];
self.slider = slider;
}
return self;
}

分析数据,设置分段值

那么就有了Slider的控件了。滑动滑竿,打印数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)sliderValueChanged:(UISlider *)slider{

NSLog(@"%@", @(slider.value));
}
/*
->0
->0.2947368
->0.2947368
->0.368421
->0.4421053
->0.4912281
->0.5526316
->0.5894737
->0.6631579
->0.7368421
->0.7859649
->0.8350877
..............
->0.9824561
->1.031579
*/

知道的数据,接下来就是对数据的分析了,看了数据我们都知道是从0到7,别问我为什么知道。但是我们的需求的分段的标度尺的值都是不一样的,比如第一段:0~10万元,间隔是1万元。那么第二段:10~100万元,间隔是10万元。第三段:100~1000万元,间隔是100万元。。。

如果是统一的间隔,那是分分钟的事情,但是间隔不一样怎么办呢?
唯有分析数据了,比前面的

1
2
3
4
5
6
7
8
9
10
11
12
13
->0
->0.2947368
->0.2947368
->0.368421
->0.4421053
->0.4912281
->0.5526316
..........
->1.0000
我先获取前面的一个小数点,那就变成 0.1 0.2 0.3....1.0
这些数乘以10,就变成了从110,OK,完成第一分段
同样的,第二段的数据是 1.1 1.2 1.3 1.4....2.0 1.3....,吧这些数据减去1,再成100,那么就变成10~100,以此类推,每一分段减去前面的分段值再乘以相对应的倍数
注意:有几个值是比较特殊的,0470代表的是0元,不是0万元,4是万跟亿之间的跨度,7是其他值。都要做特殊处理

但是有这么一个事情,滑动的幅度是慢慢的,中间的值控不能精确匹配到,比如100这个数,可能匹配到的是99.99999,但是这不是很好的体验,我最终想到了 四舍五入的方法。

1
2
3
4
5
6
7
8
9
10
//格式话小数 四舍五入类型 “0.000”
- (NSString *) decimalwithFormat:(NSString *)format numberValue:(NSNumber *)numberValue
{
float value = [numberValue floatValue];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];

[numberFormatter setPositiveFormat:format];

return [numberFormatter stringFromNumber:[NSNumber numberWithFloat:value]];
}

我们从监听他的值那里做处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (void)sliderValueChanged:(UISlider *)slider{

NSString *numStr = [NSString stringWithFormat:@"%2.1f",slider.value];
float num = [numStr floatValue];
NSString *result = @"";
if (num == 0) {
result = @"0元";
} else if (num>0 && num <= 1){
result = [NSString stringWithFormat:@"%@万元", [self decimalwithFormat:@"0" numberValue:@(num * 10)]];
} else if (num>1 && num <= 2){
result = [NSString stringWithFormat:@"%@万元", [self decimalwithFormat:@"0" numberValue:@((num - 1) * 100)]];
} else if (num>2 && num <= 3){
result = [NSString stringWithFormat:@"%@万元",[self decimalwithFormat:@"0" numberValue:@((num - 2) * 1000)]];
} else if (num>3 && num < 4){
result = [NSString stringWithFormat:@"%@万元", [self decimalwithFormat:@"0" numberValue:@((num - 3) * 10000)]];
} else if (num == 4){
result = [NSString stringWithFormat:@"%@亿元", [self decimalwithFormat:@"0" numberValue:@(num - 3)]];
} else if (num>4 && num <= 5){
result = [NSString stringWithFormat:@"%@亿元", [self decimalwithFormat:@"0" numberValue:@((num - 4) * 10)]];
} else if (num>5 && num <= 6){
result = [NSString stringWithFormat:@"%@亿元", [self decimalwithFormat:@"0" numberValue:@((num - 5) * 100)]];
} else if (num>6 && num < 7){
result = [NSString stringWithFormat:@"%@亿元", [self decimalwithFormat:@"0" numberValue:@((num - 6) * 1000)]];
} else if (num == 7){
result = [NSString stringWithFormat:@"%@亿元以上", [self decimalwithFormat:@"0" numberValue:@((num - 6) * 1000)]];
}
}

分段值,设置完毕。

设置标尺和标注

1
2
3
4
/**
标尺文字
*/

@property (nonatomic, strong) NSArray<NSString *> *rulerArr;

在.m文件中方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- (void)layoutSubviews{
[super layoutSubviews];
// 移除所有控件
[self removeAllSubviews];
// 添加slider
[self addSubview:self.slider];
[self.slider setFrame:0 y:0 w:self.width h:20];

[self bringSubviewToFront:self.slider];

__weak PriceSliderView *weakSelf = self;
// 计算平均每个分段的饿宽度
CGFloat width = self.slider.width / self.slider.maximumValue;
// 遍历标注数组
[self.rulerArr enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL * _Nonnull stop) {
@autoreleasepool {
idx++;
// 竖线
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [ZKBTools TColor:@"#33aacc"];
[label setFrame:idx * width + 10 y:weakSelf.slider.botm - 12 w:1 h:17];
[weakSelf insertSubview:label belowSubview:weakSelf.slider];

// 标注
UILabel *titleLabel = [[UILabel alloc] init];
[titleLabel setFrame:(idx * width - width/2 - 5)+10 y:label.botm+2 w:width+10 h:20];
titleLabel.text = title;
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.textColor = [ZKBTools TColor:@"#33aacc"];
titleLabel.font = TGSystemFontText;
[weakSelf insertSubview:titleLabel belowSubview:weakSelf.slider];
}
}];
}

OK,完成

代理回调

1
2
3
4
@optional
- (void)priceSliderView:(TGPriceSliderView *)sliderView sliderValueChanged:(UISlider *)slider priceStr:(NSString *)priceStr;

@end
1
2
3
if (self.delegate && [self.delegate respondsToSelector:@selector(priceSliderView:sliderValueChanged:priceStr:)]) {
[self.delegate priceSliderView:self sliderValueChanged:slider priceStr:result];
}

设置默认值

1
2
3
4
/**
设置默认选中的值,只能判断万跟亿(暂时没做)
*/

@property (nonatomic, copy) NSString *strValue;

在.m文件中重写set方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
- (void)setStrValue:(NSString *)strValue{
_strValue = strValue;
if (strValue.length < 2) return;
NSString *subStr = @"";
float result = 0.0;
if ([strValue containsString:@"万"]) {
NSRange rang = [strValue rangeOfString:@"万"];
subStr = [strValue substringToIndex:rang.location];
if (subStr.length == 0) return;
NSInteger num = [subStr integerValue];
if (num>0 && num <= 10) { //0-10万
result = (num / 10.0);
} else if (num > 10 && num<= 100){//10-100万
result = (num / 100.0);
result += 1;
} else if (num > 100 && num<= 1000){//100-1000万
result = (num / 1000.0);
result += 2;
} else if (num > 1000 && num< 10000){//1000万-1亿
result = (num / 10000.0);
result += 3;
}
}else if ([strValue containsString:@"亿以上"]){
//1000亿以上
result = 7.0;
} else if ([strValue containsString:@"亿"]){
NSRange rang = [strValue rangeOfString:@"亿"];
subStr = [strValue substringToIndex:rang.location];
if (subStr.length == 0) return;
NSInteger num = [subStr integerValue];
if (num>0 && num <= 10) { //0-10亿
result = num / 10.0;
result += 4;
} else if (num > 10 && num<= 100){//10-100亿
result = num / 100.0;
result += 5;
} else if (num > 100 && num< 1000){//100-900亿
result = num / 1000.0;
result += 6;
}
} else {
result = 0.0;
}

[_slider setValue:result animated:YES];

}

使用

在ViewController中初始化并添加视图

1
2
3
4
5
PriceSliderView  *slider = [[PriceSliderView alloc] init];
slider.rulerArr = @[@"10万", @"", @"1000万", @"1亿", @"", @"100亿"];
slider.delegate = self;
slider.frame = CGRectMake(0, 100, self.view.frame.size.width, 45);
[self.view addSubview:slider];