Как заставить UISlider произвести хорошие округленные числа экспоненциально?

Я реализую UISlider, которым пользователь может управлять для установки расстояния. Я никогда не использовал CocoaTouch UISlider, но использовал другие ползунки платформ, обычно существует переменная для установки "шага" и других свойств "помощника".

Документация для соглашений о UISlider только с макс. значением и минимальным значением и выводом всегда является 6 десятичными плаваниями с линейной зависимостью к позиции "ползунка nob". Я предполагаю, что должен буду реализовать желаемую функциональность шаг за шагом.

Пользователю минимальный диапазон значений / макс. значения колеблются от 10 м до 999 км, я пытаюсь реализовать это экспоненциальным способом, который будет чувствовать себя естественным для пользователя. Т.е. пользователь испытывает чувство управления значениями, большими или маленькими. Также то, что "вывод" имеет рыночную стоимость. Значения как 10 м 200 м 2.5 км 150 км и т.д. вместо 1,2342356 м или 108,93837756 км.

Я хотел бы за размер шага увеличиться на 10 м для первых 200 м, затем возможно, на 50 м до 500 м, затем при передаче значения на 1 000 м, он начинает иметь дело с Километрами, таким образом это - размер шага = 1 км вплоть до 50 км, затем возможно, 25-километровые шаги и т.д.

Любым путем я иду об этом, я заканчиваю тем, что делал большое округление и много вычислений, перенесенных в forrest того, если операторы и преобразования NSString/Number, каждый раз пользователь перемещает ползунок просто немного.

Я надеялся, что кто-то мог предоставить мне немного справки вдохновения/математики или сделать меня знающий о более минимизированном подходе к решению этой проблемы.

Моя последняя идея состоит в том, чтобы заполнить и выстроить с 100 строковыми значениями, затем иметь значение интервала ползунка, соответствуют строке, это не очень гибко, но выполнимо.

Заранее спасибо за любую данную справку:)

7
задан RickiG 11 May 2010 в 15:12
поделиться

4 ответа

Самый простой ответ - использовать сегментированный элемент управления с различными "размерами шага". В зависимости от того, какую опцию выберет пользователь, такой размер шага будет у вашего слайдера. Я бы даже порекомендовал, что это, возможно, более удобный для пользователя способ подхода :).

Не стесняйтесь использовать Dapp, чтобы поиграть с внешним видом вашего приложения и посмотреть, как сегментированный элемент управления может вписаться в дизайн.

Однако... вы хотели более компактного подхода ;).

Я начал писать 10 или около того необходимых шагов, но остановился, когда понял, что вы, вероятно, уже пришли к похожему решению. Ваша идея со строковым массивом хороша, я полагаю, вы просто преобразуете значение ползунка в целое число и возьмете соответствующий индекс из массива?

Иногда программисты заходят слишком далеко в своих подходах к решению проблемы. Да, строковый массив - не самое "гибкое" решение, но оно быстрое! И я бы сказал, что даже гениальное математическое решение не настолько гибкое, как вам кажется. Кроме того, если вы не планируете менять значения в ближайшее время и вам не нужны разные диапазоны ползунков на разных ползунках, то имеет смысл просто создать статический массив.

Удачи! :)

0
ответ дан 7 December 2019 в 05:19
поделиться

Решение для быстрого масштабирования включает три специальных метода:

- (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: мог бы быть более эффективным.

Что касается скорости, я уверен, что это быстрее, чем извлечение объектов из массива. Фактическое поведение ползунка может показаться немного нестабильным, и нет особого контроля над тем, какие именно значения доступны с помощью ползунка, поэтому он может не делать именно то, что вы хотите. Использование действительно высоких мощностей, казалось, сделало его более полезным.

5
ответ дан 7 December 2019 в 05:19
поделиться
+ (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 км» и обновляет делегата числом расстояния в метрах для использования при сортировке моих результатов с помощью предиката.

0
ответ дан 7 December 2019 в 05:19
поделиться

Чтобы сделать это правильно, вы хотите, чтобы ваш ползунок представлял экспоненты. Так, например, если вам нужен масштаб от 10 до 100000, вам нужно, чтобы ваш слайдер имел диапазон от 1 (10 = 10 ^ 1) до 5 (100000 = 10 ^ 5). Вы можете установить шаг ползунка на дробное значение, чтобы обеспечить желаемую точность. В моем примере я буду использовать минимум 20 000 и максимум 20 000 000 для вывода (потому что это то, что мне нужно, когда я садился разобраться в этом). Поскольку я в основном собираюсь увеличить в 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 в обеих функциях, чтобы оно соответствовало вашей базовой сумме. Если ваш максимум должен быть получен по показателю, отличному от 10, измените 10, а также максимум (показатель степени). Жить будет легче, если вы подниметесь вверх на десять.

0
ответ дан 7 December 2019 в 05:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: