iOS, как заставить слайдер останавливаться в дискретных точках

Я хотел бы, чтобы ползунок останавливался в дискретных точках, которые представляют целые числа на временной шкале. Как лучше всего это сделать? Мне не нужны промежуточные значения. Было бы здорово, если бы ползунок мог «привязываться» к положению в каждой отдельной точке.


person gonzobrains    schedule 16.08.2011    source источник


Ответы (5)


Чтобы ползунок «застрял» в определенных точках, ваш контроллер представления должен в методе valueChanged, связанном с ползунком, определить соответствующее округление от значения ползунка, а затем использовать setValue:animated: для перемещения ползунка в соответствующее место. Итак, если ваш ползунок перемещается от 0 до 2, а пользователь меняет его на 0,75, вы предполагаете, что это должно быть 1, и устанавливаете значение ползунка на это значение.

person jrturton    schedule 16.08.2011
comment
Как говорит Натан ниже, используйте «Подправить внутри», потому что он будет мерцать при перетаскивании, если вы используете valueChanged. - person Zenuka; 18.01.2013
comment
Это применимо только в том случае, если ползунок непрерывен, но да, в этом случае это лучшее решение. - person jrturton; 04.12.2013

Шаги, которые я предпринял здесь, были почти такими же, как указано в ответе jrturton, но я обнаружил, что ползунок довольно заметно отстает от моих движений. Вот как я это сделал:

Поместите ползунок в представление в Интерфейсном Разработчике. Установите минимальные/максимальные значения ползунка. (я использовал 0 и 5)

В файле .h:

@property (strong, nonatomic) IBOutlet UISlider *mySlider;
- (IBAction)sliderChanged:(id)sender;

В файле .m:

- (IBAction)sliderChanged:(id)sender 
{
    int sliderValue;
    sliderValue = lroundf(mySlider.value);
    [mySlider setValue:sliderValue animated:YES];
}

После этого в Interface Builder я подключил событие «Touch Up Inside» для ползунка к владельцу файла, а не к «Value Changed». Теперь это позволяет мне плавно перемещать ползунок и привязываться к каждому целому числу, когда мой палец поднимается.

Спасибо @jrturton!

ОБНОВЛЕНИЕ – Swift:

@IBOutlet var mySlider: UISlider!

@IBAction func sliderMoved(sender: UISlider) {
    sender.setValue(Float(lroundf(mySlider.value)), animated: true)
}

Кроме того, если есть какая-то путаница при подключении вещей в раскадровке, я загрузил быстрый пример на github: https://github.com/nathandries/StickySlider

person Nathan Dries    schedule 14.03.2012
comment
Красиво, но округляется в меньшую сторону. lroundf будет округлять до ближайшего целого числа. - person Danyal Aytekin; 17.04.2012
comment
Я бы также использовал «Touch Up Outside». - person Zenuka; 18.01.2013
comment
Вы можете заменить mySlider.value на sender.value, поэтому вам не нужна внешняя ссылка (если у вас есть массив ползунков или что-то в этом роде) - person mgarciaisaia; 27.04.2019
comment
Вам по-прежнему нужно valueChanged, если вы хотите визуально отметить изменения. - person sabiland; 17.11.2019

Что я сделал для этого, так это сначала установил «выходную» переменную текущего значения ползунка в целое число (по умолчанию это число с плавающей запятой). Затем установите выходной номер в качестве текущего значения ползунка:

int output = (int)mySlider.value;
mySlider.value = output;

Это заставит его двигаться с шагом в 1 целое число. Чтобы заставить его двигаться в определенном диапазоне чисел, скажем, в 5 с, измените выходное значение с помощью следующей формулы. Добавьте это между первыми двумя строками выше:

int output = (int)mySlider.value;
int newValue = 5 * floor((output/5)+0.5);
mySlider.value = newValue;

Теперь ваш ползунок «прыгает» на число, кратное 5, когда вы его перемещаете.

person ctlockey    schedule 12.03.2013

Я сделал, как предложил Натан, но я также хочу обновить связанный UILabel, отображающий текущее значение в режиме реального времени, поэтому вот что я сделал:

- (IBAction) countdownSliderChanged:(id)sender
{
    // Action Hooked to 'Value Changed' (continuous)

    // Update label (to rounded value)

    CGFloat value = [_countdownSlider value];

    CGFloat roundValue = roundf(value);

    [_countdownLabel setText:[NSString stringWithFormat:@" %2.0f 秒", roundValue]];
}


- (IBAction) countdownSliderFinishedEditing:(id)sender
{
    // Action Hooked to 'Touch Up Inside' (when user releases knob)

    // Adjust knob (to rounded value)

    CGFloat value = [_countdownSlider value];

    CGFloat roundValue = roundf(value);

    if (value != roundValue) {
        // Almost 100% of the time - Adjust:

        [_countdownSlider setValue:roundValue];
    }
}

Недостаток, конечно, в том, что для каждого слайдера требуется два действия (метода).

person Nicolas Miari    schedule 16.05.2013

Версия Swift с ValueChanged и TouchUpInside.

РЕДАКТИРОВАТЬ: На самом деле вы должны подключить 3 события в этом случае:

yourSlider.addTarget(self, action: #selector(presetNumberSliderTouchUp), for: [.touchUpInside, .touchUpOutside, .touchCancel])

Я только что вставил свой код, но вы можете легко увидеть, как это делается.

private func setSizesSliderValue(pn: Int, slider: UISlider, setSliderValue: Bool)
{
    if setSliderValue
    {
        slider.setValue(Float(pn), animated: true)
    }

    masterPresetInfoLabel.text = String(
        format: TexturingViewController.createAndSendPresetNumberNofiticationTemplate,
        self.currentPresetNumber.name.uppercased(),
        String(self.currentPresetNumber.currentUserIndexHumanFriendly)
    )
}

@objc func presetNumberSliderTouchUp(_ sender: Any)
{
    guard let slider = sender as? NormalSlider else{
        return
    }

    setupSliderChangedValuesGeneric(slider: slider, setSliderValue: true)
}

private func setupSliderChangedValuesGeneric(slider: NormalSlider, setSliderValue: Bool)
{
    let rounded = roundf((Float(slider.value) / Float(presetNumberStep))) * Float(presetNumberStep)

    // Set new preset number value
    self.currentPresetNumber.current = Int(rounded)
    setSizesSliderValue(pn: Int(rounded), slider: slider, setSliderValue: setSliderValue)
}

@IBAction func presetNumberChanged(_ sender: Any)
{
    guard let slider = sender as? NormalSlider else{
        return
    }

    setupSliderChangedValuesGeneric(slider: slider, setSliderValue: false)
}
person sabiland    schedule 17.11.2019