7

我正在实现一个用户可以操纵的 UISlider 来设置距离。我从未使用过 CocoaTouch UISlider,但使用过其他框架的滑块,通常有一个变量用于设置“step”和其他“helper”属性。

UISlider 的文档仅处理最大值和最小值,并且输出始终是 6 位小数浮点数,与“滑块 nob”的位置呈线性关系。我想我将不得不逐步实现所需的功能。

对用户来说,最小/最大值范围从 10 m 到 999 Km,我试图以指数方式实现这一点,这对用户来说会感觉很自然。即用户体验到对值的控制感,无论大小。此外,“输出”具有合理的价值。10m 200m 2.5km 150 km 等值,而不是 1.2342356 m 或 108.93837756 km。

我希望前 200m 的步长增加 10m,然后可能增加 50m 到 500m,然后当通过 1000m 值时,它开始处理公里,所以它的步长 = 1 km 直到50 公里,然后可能是 25 公里的台阶等。

无论如何,我最终都会在 if 语句和 NSString/Number 转换的 forrest 中进行大量舍入和大量计算,每次用户移动滑块时。

我希望有人能给我一些灵感/数学帮助,或者让我意识到解决这个问题的更精简的方法。

我的最后一个想法是用 100 个字符串值填充和排列,然后让滑块 int 值对应一个字符串,这不是很灵活,但可行。

预先感谢您提供的任何帮助:)

4

6 回答 6

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:and方法应该检查不受支持的unscaleValue:值,我相信sliderChange:方法会更有效。

就速度而言,我确信这比将对象拉出数组要快。实际的滑块行为可能感觉有点不稳定,并且对于滑块可用的确切值没有太多控制,因此它可能无法完全按照您的意愿行事。使用非常高的权力似乎使它更有用。

于 2010-05-12T21:02:25.827 回答
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]; 
}
于 2011-07-27T16:39:11.313 回答
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];

}
于 2012-03-07T14:33:03.173 回答
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 m”或“1.5 km”,并使用以米为单位的距离数更新委托,以便在使用谓词对我的结果进行排序时使用。

于 2010-05-14T12:33:18.763 回答
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)。我将使用 0.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 以匹配您的基本金额。如果您的最大值必须由 10 以外的指数得出,请更改 10 以及最大值(指数)。如果你上升十次方,生活会更轻松。

于 2010-07-21T23:20:04.857 回答
0

最简单的答案是使用具有不同“步长”的分段控件。根据用户选择的选项,您的滑块将具有什么步长。我什至建议这可能是一种更用户友好的方式来处理它:)。

随意使用Dapp来玩弄您的应用程序的外观,看看分段控件如何适合设计。

但是...您想要一种更精简的方法;)。

我开始编写所需的 10 个左右的步骤,但当我意识到您可能已经找到了类似的解决方案时,我停止了。您的字符串数组想法很好,我假设您只需将滑块值转换为整数并从数组中获取相关索引?

有时,作为程序员,我们在解决问题的方法上走得太远了。是的,字符串数组不是最“灵活”的解决方案,但它很快!而且,我认为即使是天才的数学解决方案也没有你想象的那么灵活。此外,如果您不打算很快更改值并且不需要不同滑块上的不同滑块范围,那么创建一个静态数组是有意义的。

祝你好运!:)

于 2010-05-11T18:47:54.543 回答