iPhone: Как определить конец перетаскивания слайдера?

96

Как определить событие, когда пользователь закончил перетаскивание указателя ползунка?

DroidHeaven
источник
1
Используйте: [слайдер addTarget: самостоятельное действие: @selector (sliderStoppedDragging :) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
Генри Соу

Ответы:

180

Если вам не нужны данные между перетаскиванием, вы должны просто установить:

[mySlider setContinuous: NO];

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

Версия Swift 5 :

mySlider.isContinuous = false
Рок Ярк
источник
2
Это лучший ответ на этот вопрос. Я бы хотел, чтобы мы изменили ответ на этот вопрос.
M. Porooshani
1
i.imgur.com/0Edd2xe.png?1 XCode версии 6.x имеет эту функцию установки setContinuous через саму среду IDE.
Abhijeet
1
Да, лучший ответ такой.
sabiland
3
Отличный ответ. Вот код Swift 4:self.mySlider.isContinuous = false
Марко Вебер,
2
Автор не об этом спрашивает. Он хочет непрерывно скользить, а также хочет знать, когда остановиться.
lbsweek 05
120

Вы можете добавить действие, которое принимает два параметра, отправителя и событие, для UIControlEventValueChanged:

[slider addTarget:self action:@selector(onSliderValChanged:forEvent:) forControlEvents:UIControlEventValueChanged]

Затем проверьте фазу сенсорного объекта в вашем обработчике:

- (void)onSliderValChanged:(UISlider*)slider forEvent:(UIEvent*)event {     
    UITouch *touchEvent = [[event allTouches] anyObject];
    switch (touchEvent.phase) {     
        case UITouchPhaseBegan:
            // handle drag began
            break;
        case UITouchPhaseMoved:
            // handle drag moved
            break;
        case UITouchPhaseEnded:
            // handle drag ended
            break;
        default:
            break;
    }
}

Swift 4 и 5

slider.addTarget(self, action: #selector(onSliderValChanged(slider:event:)), for: .valueChanged)
@objc func onSliderValChanged(slider: UISlider, event: UIEvent) {
    if let touchEvent = event.allTouches?.first {
        switch touchEvent.phase {
        case .began:
            // handle drag began
        case .moved:
            // handle drag moved
        case .ended:
            // handle drag ended
        default:
            break
        }
    }
}

Обратите внимание, что в Интерфейсном Разработчике при добавлении действия у вас также есть возможность добавить к действию параметры отправителя и события.

Девин Питчер
источник
1
Прекрасно работает! Откуда вы взяли для этого источник?
Рой Мулиа
2
спасибо @RoiMulia, не помню, где впервые увидел, уже много лет использую в слайдерах. Иногда я использую его, чтобы игнорировать изменение в UITouchPhaseEnded, поскольку значение имеет тенденцию к скачку, когда пользователь поднимает палец.
Девин Питчер,
2
Не забудьте установить isContinuous = trueв вашем UISlider.
krlbsk
2
Это отличное решение, однако у него есть проблема с отменой касания. Несмотря на то, что в перечислении touchEvent есть событие «cancelled», оно не запускается при отмене касания. Поэтому я рекомендую также добавить прослушиватель для события touchCancel из Slider. Это должно охватывать все возможности.
bnussey
2
Я видел, что иногда фаза может идти: началась, стояла, переместилась, но потом никогда не заканчивалась и не отменялась. Это проблематично для моего варианта использования, поскольку я ожидал, что каждое взаимодействие завершится или будет отменено. Исправление указано выше: используйте отдельную цель / действие отмены касания.
Jordan H
71

Я использую уведомления «Подкрашивание изнутри» и «Подкрашивание снаружи».

Разработчик интерфейса:

Подключите оба уведомления в Интерфейсном Разработчике к вашему методу получения. Метод может выглядеть так:

- (IBAction)lengthSliderDidEndSliding:(id)sender {
    NSLog(@"Slider did end sliding... Do your stuff here");
}

В коде:

Если вы хотите подключить его программно, у вас будет что-то вроде этого в вашем viewWillAppear (или там, где вам подходит) вызов:

[_mySlider addTarget:self
              action:@selector(sliderDidEndSliding:) 
    forControlEvents:(UIControlEventTouchUpInside | UIControlEventTouchUpOutside)];

Метод получения будет выглядеть так:

- (void)sliderDidEndSliding:(NSNotification *)notification {
     NSLog(@"Slider did end sliding... Do your stuff here");
}
Томас
источник
19

Поскольку UISliderэто подкласс UIControl, вы можете установить для него цель и действие UIControlEventTouchUpInside.

Если вы хотите сделать это в коде, это будет выглядеть так:

[self.slider addTarget:self action:@selector(dragEndedForSlider:)
    forControlEvents:UIControlEventTouchUpInside];

Это отправит вам dragEndedForSlider:сообщение, когда касание закончится.

Если вы хотите сделать это в своем наконечнике, вы можете щелкнуть слайдер, удерживая клавишу Control, чтобы открыть меню подключений, а затем перетащить его из гнезда «Touch Up Inside» на целевой объект.

Вы также должны добавить цель и действие для UIControlEventTouchUpOutsideи для UIControlEventTouchCancel.

Роб Мэйофф
источник
1
@rob mayoff Извините, но вам нужно использовать UIControlEventTouchUpOutside. В противном случае селектор не будет вызываться, если ваш палец не находится на слайдере, когда вы закончите перетаскивание.
user3164248
2
Поведение UISliderизменилось с тех пор, как я написал этот ответ.
Роб Мэйофф
Могу подтвердить, что вам также необходимо зарегистрировать обработчик для UIControlEventTouchUpOutside в iOS 9.
lms
Мне никогда не удавалось вызвать UIControlEventTouchCancelобработчик в iOS 9. Но я могу вызвать UIControlEventTouchUpInsideи UIControlEventTouchUpOutsideтолько.
петрсын
17

Swift 5 и Swift 4

  1. Добавить цель для touchUpInsideи touchUpOutsideсобытий. Вы можете сделать это программно или из раскадровки. Вот как вы это делаете программно

    slider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
    
  2. Напишите свою функцию для обработки конца перетаскивания ползунка

    func sliderDidEndSliding() {
        print("end sliding")
    }
    
Гай Дахер
источник
Здравствуйте. Как приостановить видео при перетаскивании?
kemdo
Это не определяет, обязательно ли произошло перетаскивание, и может быть запущено простым касанием без перетаскивания.
Chewie The Chorkie
9

Ты можешь использовать:

- (void)addTarget:(id)target action:(SEL)action 
                   forControlEvents:(UIControlEvents)controlEvents  

для обнаружения событий touchDown и touchUp в UISlider

Мудит Баджпай
источник
5

Swift 3 ответ

У меня была такая же проблема, и в конце концов это заработало, так что, возможно, это кому-то поможет. Подключите your_Slider к «Value Changed» в раскадровке, и при перемещении слайдера «Slider Touched» активирован, а когда отпущен «Slider Released».

@IBAction func your_Slider(_ sender: UISlider) {
    if (yourSlider.isTracking) {
        print("Slider Touched")
    } else {
        print("Slider Released")
    }
}
Энди
источник
2
Хорошее решение, но осторожное, потому что Slider Released вызывается при начале и окончании перетаскивания
Гай Дахер
и иногда не называется "Slider Released" при выпуске
Вадим
4

Подключите Touch Up InsideиValue Changed

введите описание изображения здесь

Abo3atef
источник
4

Swift 3.1

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

Для этого я расширил ответ Энди выше, в котором используется isTrackingсвойство ползунка . Мне нужно было записать два состояния: sliderHasFinishedTrackingи sliderLastStoredValue.

Мой код правильно:

  • не запускает действие при запуске перетаскивания

  • запускает действие, если пользователь подталкивает ползунок только одним нажатием (то есть, что isTrackingостается false)


class SliderExample: UIViewController {
  var slider: UISlider = UISlider()
  var sliderHasFinishedTracking: Bool = true
  var sliderLastStoredValue: Float!

  override func loadView() {
    super.loadView()

    slider.minimumValue = 100.0
    slider.maximumValue = 200.0
    slider.isContinuous = true
    slider.value = 100.0
    self.sliderLastStoredValue = slider.value
    slider.addTarget(self, action: #selector(respondToSlideEvents), for: .valueChanged)
    // add your slider to the view however you like
  }

  func respondToSlideEvents(sender: UISlider) {
    let currentValue: Float = Float(sender.value)
    print("Event fired. Current value for slider: \(currentValue)%.")

    if(slider.isTracking) {
      self.sliderHasFinishedTracking = false
      print("Action while the slider is being dragged ⏳")
    } else {
      if(self.sliderHasFinishedTracking && currentValue == self.sliderLastStoredValue){
        print("Slider has finished tracking and its value hasn't changed, " +
              "yet event was fired anyway. 🤷") // No need to take action.
      } else {
        self.sliderHasFinishedTracking = true
        print("Action upon slider drag/tap finishing ⌛️")
      }
    }

    self.sliderLastStoredValue = currentValue
  }
}
Джейми Берч
источник
4

В Swift 4 вы можете использовать эту функцию

1 Первый шаг: - Добавление цели в слайдер

self.distanceSlider.addTarget(self, action: #selector(self.sliderDidEndSliding(notification:)), for: ([.touchUpInside,.touchUpOutside]))

2 Второй шаг: - Создайте функцию

@objc func sliderDidEndSliding(notification: NSNotification)
{
   print("Hello-->\(distanceSlider.value)")
}
пансора абхай
источник
2

Возможно, вам следует добавить цель для событий UIControlEventTouchUpInside 、 UIControlEventTouchUpOutside 、 UIControlEventTouchCancel.

Я сталкивался с той же проблемой раньше, потому что я не добавляю цель для события UIControlEventTouchCancel .

Чжуомин
источник
1

Недавно у меня была аналогичная проблема. Вот что я сделал в Swift:

    theSlider.continuous = false;

Код, содержащий это непрерывное значение, читает:

public var continuous: Bool // if set, value change events are generated
    // any time the value changes due to dragging. default = YES

По умолчанию, похоже, ДА (правда). Установка его в false делает то, что вы хотите.

Евджан Мустафа
источник
0

Попробуйте вот так

customSlider.minimumValue = 0.0;
    customSlider.maximumValue = 10.0;
[customSlider addTarget:self action:@selector(changeSlider:) forControlEvents:UIControlEventValueChanged];


-(void)changeSlider:(id)sender{
    UISlider *slider=(UISlider *)sender;
    float sliderValue=(float)(slider.value );
NSLog(@"sliderValue = %f",sliderValue);
}
Радж Суббиа
источник
Это отправляет действие каждый раз, когда ползунок перемещается, а не только когда перетаскивание закончилось.
Роб Мэйофф
0

RxSwift:

self.slider.rx.controlEvent([.touchUpInside, .touchUpOutside])
    .bind(to: self.viewModel.endSlidingSlider)
    .disposed(by: self.disposeBag)
Адам Смака
источник
0

Создайте действие и выход для ползунка (или вы можете привести тип отправителя из действия в UISlider) и в пользовательском интерфейсе снимите флажок «Непрерывные обновления». Таким образом, мы получим значение ползунка только тогда, когда ползунок перестанет перетаскивать.

@IBAction func actionSlider(_ sender: Any) {
   let value = sliderSpeed.value.rounded()
}

введите описание изображения здесь

Самир Джагтап
источник