Я хотел бы, чтобы ползунок останавливался в дискретных точках, которые представляют целые числа на временной шкале. Как лучше всего это сделать? Мне не нужны промежуточные значения. Было бы здорово, если бы ползунок мог «привязываться» к положению в каждой отдельной точке.
iOS, как заставить слайдер останавливаться в дискретных точках
Ответы (5)
Чтобы ползунок «застрял» в определенных точках, ваш контроллер представления должен в методе valueChanged, связанном с ползунком, определить соответствующее округление от значения ползунка, а затем использовать setValue:animated: для перемещения ползунка в соответствующее место. Итак, если ваш ползунок перемещается от 0 до 2, а пользователь меняет его на 0,75, вы предполагаете, что это должно быть 1, и устанавливаете значение ползунка на это значение.
Шаги, которые я предпринял здесь, были почти такими же, как указано в ответе 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
mySlider.value
на sender.value
, поэтому вам не нужна внешняя ссылка (если у вас есть массив ползунков или что-то в этом роде)
- person mgarciaisaia; 27.04.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, когда вы его перемещаете.
Я сделал, как предложил Натан, но я также хочу обновить связанный 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];
}
}
Недостаток, конечно, в том, что для каждого слайдера требуется два действия (метода).
Версия 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)
}