我正在实现一个UISlider,用户可以通过操作来设置距离。 我从来没有使用过CocoaTouch UISlider,但是使用过其他框架的滑块,通常有一个变量用于设置“step”和其他“helper”属性。
UISlider的文档只处理最大值和最小值,输出总是一个6位十进制浮点数,与“滑块nob”的位置成线性关系。我想我将不得不一步一步地实现所需的功能。
对于用户来说,最小/最大值范围从10米到999公里,我试图以指数方式实现这一点,这对用户来说是自然的。即用户体验到对价值的控制感,无论大小。此外,“输出”具有合理的价值。值10m 200m 2.5km 150 km等,而不是1.2342356 m或108.93837756 km。
我希望步长增加10米,前200米,然后可能增加50米到500米,然后当通过1000米时,它开始处理千米,所以它是步长= 1公里直到50公里,然后可能是25公里步等。
无论如何,我最终都会进行大量的舍入和大量的计算 if语句和NSString / Number转换的forrest,每次用户移动滑块一点。
我希望有人能借给我一些灵感/数学帮助或让我意识到 一种更精益的方法来解决这个问题。
我的最后一个想法是使用100个字符串值填充和数组,然后让滑块int值对应一个字符串,这不是很灵活,但可行。
提前感谢您提供的任何帮助:)
答案 0 :(得分:5)
快速扩展解决方案涉及三种特殊方法:
- (CGFloat)scaleValue:(CGFloat)value {
return pow(value, 10);
}
- (CGFloat)unscaleValue:(CGFloat)value {
return pow(value, 1.0 / 10.0);
}
- (CGFloat)roundValue:(CGFloat)value {
if(value <= 200) return floor(value / 10) * 10;
if(value <= 500) return floor(value / 50) * 50;
if(value <= 1000) return floor(value / 100) * 100;
if(value <= 50000) return floor(value / 1000) * 1000;
return floor(value / 25000) * 25000;
}
对滑块更改的反应类似于:
- (void)sliderChange:(id)sender {
CGFloat value = mySlider.value;
value = [self scaleValue:value];
value = [self roundValue:value];
valueLabel.text = [NSString stringWithFormat:@"%f", value];
}
您可以使用以下代码进行初始化:
mySlider.maximumValue = [self unscaleValue:999000];
mySlider.minimumValue = [self unscaleValue:10];
我完成上述所有工作没有任何问题,但它可以使用一些防弹。 scaleValue:
和unscaleValue:
方法应检查不受支持的值,并确保sliderChange:
方法更有效。
就速度而言,我确信这比从数组中拉出对象更快。实际的滑块行为可能会感觉有点不稳定,并且没有太多控制滑块可用的确切值,因此可能无法完全按照您的要求进行操作。使用真正的高权力似乎使它更有用。
答案 1 :(得分:2)
您还可以设置“步长”来构建滑块,如下所示:
- (void) sliderChanged:(UISlider *)slider
{
int value = (int)[slider value];
int stepSize = 500.0f;
value = value - value%stepSize;
[km setText:[NSString stringWithFormat:@"%d Km",value]];
}
与此解决方案一起,您可以放置两个按钮(+和 - )来调整滑块值:
- (void) incrementKm:(UIButton *)button
{
[kmSlider setValue:[kmSlider value] + 500.0f animated:YES];
[self sliderChanged:kmSlider];
}
- (void) decrementKm:(UIButton *)button
{
[kmSlider setValue:[kmSlider value] - 500.0f animated:YES];
[self sliderChanged:kmSlider];
}
答案 2 :(得分:1)
如果您希望滑块选择可变长度的选项数组,则可以选择以下选项:
-(void)setupSlider {
//this has to be (scale - 1) from sliderChanged selector to avoid index out of bounds error
_sldOptionPicker.maximumValue = 99;
//should be zero
_sldOptionPicker.minimumValue = 0;
//can be any value 0 to 99
_sldOptionPicker.value = 0;
}
-(IBAction)sliderChanged:(id)sender {
float scale = 100 / [optionsArray count];
int index = (int)(_sldOptionPicker.value / scale);
Option *mySelectedOption = (Option*)[optionsArray objectForIndex:index];
}
答案 3 :(得分:0)
最简单的答案是使用具有不同“步长”的分段控件。根据用户选择的选项,滑块将具有哪个步长。我甚至建议这可能是一种更友好的方式来接近它:)。
随意使用Dapp来播放应用外观,并了解分段控件如何与设计相符。
然而......你想要更精简的方法;)。
我开始编写所需的10个左右的步骤,但当我意识到你可能已经找到类似的解决方案时,我停了下来。您的字符串数组的想法很好,我假设您只需将滑块值转换为整数并从数组中获取相关索引?
有时作为程序员,我们对问题的解决方法走得太远了。是的,字符串数组不是最“灵活”的解决方案,但速度很快!而且,我认为即使是天才的数学解决方案也不像你想象的那么灵活。此外,如果您不打算很快改变值,并且不需要在不同的滑块上使用不同的滑块范围,那么创建一个静态数组是有意义的。
祝你好运! :)答案 4 :(得分:0)
+ (NSArray*) getSliderNumbers {
NSArray *sliderNumbers = [NSArray arrayWithObjects:@"10",
@"20",
@"30",
@"40",
@"50",
@"60",
@"70",
@"80",
@"90",
@"100",
@"150",
@"200",
@"250",
@"300",
@"350",
@"400",
@"450",
@"500",
@"600",
@"700",
@"800",
@"900",
@"1",
@"1.5",
@"2.0",
@"2.5",
@"3.0",
@"3.5",
@"4",
@"4.5",
@"5",
@"5.5",
@"6",
@"6.5",
@"7",
@"7.5",
@"8",
@"8.5",
@"9",
@"9.5",
@"10",
@"15",
@"20",
@"25",
@"30",
@"35",
@"40",
@"45",
@"50",
@"55",
@"60",
@"65",
@"70",
@"75",
@"80",
@"85",
@"90",
@"95",
@"100",
@"200",
@"300",
@"400",
@"500",
@"600",
@"700",
@"800",
@"900",
nil];
return sliderNumbers;
}
上面的在实例化时被加载到一个数组中:
设置滑块:
customSlider.minimumValue = 0.0f;
customSlider.maximumValue = (CGFloat)[sliderNumbers count] - 1;
customSlider.continuous = YES;
customSlider.value = customSlider.maximumValue;
调用UIControlEventValueChanged
- (void) sliderMove:(UISlider*) theSlider {
NSInteger numberLookup = lroundf([theSlider value]);
NSString *distanceString = [sliderNumbers objectAtIndex:numberLookup];
CGFloat distanceInMeters;
if (numberLookup > 21) {
[self.indicator.indicatorLabel setText:[NSString stringWithFormat:@"%@ km", distanceString]];
distanceInMeters = [distanceString floatValue] * 1000;
} else {
[self.indicator.indicatorLabel setText:[NSString stringWithFormat:@"%@ m", distanceString]];
distanceInMeters = [distanceString floatValue];
}
if (oldDistanceInMeters != distanceInMeters) {
[self.delegate distanceSliderChanged:distanceInMeters];
oldDistanceInMeters = distanceInMeters;
}
}
这甚至负责格式化用户界面的字符串,例如“200米”或“1.5公里”并使用以米为单位的距离数更新代表,以便在使用谓词对结果进行排序时使用。
答案 5 :(得分:0)
为了做到这一点,您希望滑块代表指数。因此,例如,如果您想要10-100000的比例,您希望滑块的范围为1(10 = 10 ^ 1)到5(100,000 = 10 ^ 5)。您可以将滑块上的步进设置为分数,以便为您提供所需的精度。对于我的例子,我将使用最小20,000和最大20,000,000的输出(因为这是我在坐下来想出这个时所需要的)。因为我基本上要从min到max增加1000倍我想要10 ^ 3,所以我的滑块将是0-3(10 ^ 0评估为1)。我将使用.001步进,因此总共有3000个可能的位置。以下是完成此操作所需的代码:
$("#amount-slider").slider({
value:20000,
min: 0,
max: 3,
step:.001,
slide: function(event, ui) {
$("#amount").val(Math.pow(10, ui.value)*20000);
}
});
假设您想要此函数的反转,因此您可以在给定一些外部输入的情况下设置滑块位置。然后你想使用对数:
var amtVal = parseFloat($("#amount").val());
$('#amount-slider').slider('value', ((Math.log(amtVal/20000)/Math.log(10))));
您需要在两个功能中调整20000以匹配您的基本金额。如果你的max必须通过10以外的指数得出,则改变10以及max(指数)。如果你以10的力量上升,生活会更容易。