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

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


person DroidHeaven    schedule 22.02.2012    source источник
comment
Используйте: [слайдер addTarget: самостоятельное действие: @selector (sliderStoppedDragging :) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];   -  person Henry Sou    schedule 29.06.2018
comment
Даааааааааааааааааааааа! Благодарю вас!   -  person Markus    schedule 27.11.2020


Ответы (16)


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

[mySlider setContinuous: NO];

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

Версия Swift 5:

mySlider.isContinuous = false
person Rok Jarc    schedule 22.02.2012
comment
Это лучший ответ на этот вопрос. Я бы хотел, чтобы мы изменили ответ на этот вопрос. - person M. Porooshani; 10.09.2015
comment
i.imgur.com/0Edd2xe.png?1 XCode версии 6.x возможность установки setContinuous через саму IDE. - person Abhijeet; 14.09.2015
comment
Да, лучший ответ такой. - person sabiland; 17.01.2016
comment
В Xcode 7.3 Interface Builder есть Events [x] Continuous Updates параметр для UISliderView. Снятие этого флажка устанавливает continuous в значение false / NO. - person leanne; 14.07.2016
comment
Отличный ответ. Вот код Swift 4: self.mySlider.isContinuous = false - person Marco Weber; 16.12.2017
comment
Автор не об этом спрашивает. Он хочет непрерывно скользить, а также хочет знать, когда остановиться. - person lbsweek; 05.09.2018
comment
@lbsweek: OP (автор) спрашивает ‹quote›, как определить конец перетаскивания ползунка ‹/quote›. В формулировке этого вопроса не осталось много места для маневра для свободного толкования. - person Rok Jarc; 05.09.2018
comment
@RokJarc Это нормально, согласно отзывам, это решение удовлетворяет потребности большинства разработчиков. - person lbsweek; 05.09.2018
comment
Мне нужны оба, так что это не совсем ответ на вопрос. - person Chewie The Chorkie; 06.11.2018
comment
@ChewieTheChorkie: он отвечает на вопрос OP: в этом вся суть SO ;-) - person Rok Jarc; 07.11.2018
comment
Что делать, если вам нужны данные между перетаскиванием? - person Albert Renshaw; 14.12.2018
comment
В этом случае вы оставляете свойство countinuous на ДА - состояние по умолчанию. - person Rok Jarc; 14.12.2018
comment
Это не отвечает на вопрос; он предоставляет только обходной путь, который был полезен в данном случае. - person Oscar; 18.11.2019
comment
Спасибо, ты сэкономил мне время на Fxxxing, чувак! Я борюсь с тем, какое событие обнаруживает конец перетаскивания для ползунка, и не нашел его. И меня не волнуют значения во время смены ползунка звуковой дорожки currentTime. - person ChuckZHB; 03.06.2021

Вы можете добавить действие, которое принимает два параметра, отправителя и событие, для 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
        }
    }
}

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

person Devin Pitcher    schedule 09.08.2016
comment
Прекрасно работает! Где вы взяли для этого источник? - person Roi Mulia; 29.08.2016
comment
спасибо @RoiMulia, не помню, где впервые увидел, уже много лет использую в слайдерах. Иногда я использую его, чтобы игнорировать изменение в UITouchPhaseEnded, поскольку значение имеет тенденцию к скачку, когда пользователь поднимает палец. - person Devin Pitcher; 30.08.2016
comment
Это надежный способ справиться с этим? Что делать, если в allTouches есть несколько событий, принадлежащих разным фазам? - person David; 10.03.2017
comment
@David UISlider по умолчанию имеет multipleTouchEnabled = NO. - person Devin Pitcher; 10.03.2017
comment
Не забудьте установить isContinuous = true в свой UISlider. - person krlbsk; 20.09.2017
comment
Я написал код на случай: .move и .end, теперь что происходит, это ползунок. Изображение не движется плавно. Без каких-либо вещей в .move и .end слайдер движется плавно. - person Malleswari; 04.01.2018
comment
@Malleswari, когда вы перемещаете ползунок, кейс .moved будет вызываться постоянно (т.е. много раз) в основном потоке по мере обновления положения ползунка. Таким образом, в случае .move вы не хотите выполнять интенсивную работу с процессором или вводом-выводом. - person Devin Pitcher; 05.01.2018
comment
Но у меня слайдер не плавный. Я вызываю слайдер, как этот progressSlider.addTarget (self, action: #selector (sliderTouchEvents), for: UIControlEvents.valueChanged) - person Malleswari; 05.01.2018
comment
@Malleswari, что ты делаешь в кейсе .move? Вы не должны делать ничего, что влияет на состояние ползунка или для обработки требуется более нескольких миллисекунд. - person Devin Pitcher; 05.01.2018
comment
Это отличное решение, однако у него есть проблема с отменой касания. Несмотря на то, что в перечислении touchEvent есть отмененное событие, оно не запускается при отмене касания. Поэтому я рекомендую также добавить прослушиватель для события touchCancel из слайдера. Это должно охватывать все возможности. - person bnussey; 19.07.2018
comment
@Malleswari Вы можете объявить это: private var renderTimer = Timer () А затем использовать там, где вам это нужно, как: self.renderTimer = Timer (timeInterval: 0.1, target: self, selector: #selector (AudioMessageCell.renderTimerCycle), userInfo: nil , repeat: true) Там, где вы можете фактически изменить timeInterval, уменьшите его, например, до 0,01, чтобы ваш ползунок двигался более плавно. - person timetraveler90; 18.06.2019
comment
Я видел, что иногда фаза может идти: началось, стояло, переместилось, но потом никогда не заканчивалось и не отменялось. Это проблематично для моего варианта использования, поскольку я ожидал, что каждое взаимодействие завершится или будет отменено. Исправление указано выше: используйте отдельную цель / действие отмены касания. - person Jordan H; 28.01.2020
comment
Также обратите внимание, что allTouches будет nil при увеличении / уменьшении значения с помощью VoiceOver. - person Jordan H; 28.01.2020
comment
@DevinPitcher Это, безусловно, самое обширное решение, которое я мог получить. Потрясающая работа. - person Hitit; 24.09.2020

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

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

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

- (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");
}
person thomas    schedule 03.03.2012

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

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

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

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

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

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

person rob mayoff    schedule 22.02.2012
comment
@rob mayoff Извините, но вам нужно использовать UIControlEventTouchUpOutside. В противном случае селектор не будет вызываться, если ваш палец не находится на слайдере, когда вы закончите перетаскивание. - person user3164248; 11.04.2015
comment
Поведение UISlider изменилось с тех пор, как я написал этот ответ. - person rob mayoff; 11.04.2015
comment
Можно подтвердить, что вам действительно необходимо также зарегистрировать обработчик для UIControlEventTouchUpOutside в iOS 9. - person lms; 09.06.2016
comment
Мне никогда не удавалось вызвать обработчик UIControlEventTouchCancel в iOS 9. Но я могу вызывать только UIControlEventTouchUpInside и UIControlEventTouchUpOutside. - person petrsyn; 29.09.2016

Swift 5 и Swift 4

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

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

    func sliderDidEndSliding() {
        print("end sliding")
    }
    
person Guy Daher    schedule 10.05.2017
comment
Привет. Как приостановить видео при перетаскивании? - person kemdo; 12.07.2018
comment
Это не определяет, обязательно ли когда-либо происходило перетаскивание, и может быть запущено простым касанием без перетаскивания. - person Chewie The Chorkie; 06.11.2018

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

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

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

person Mudit Bajpai    schedule 22.02.2012

Я думаю, вам нужно контрольное событие UIControlEventTouchUpInside.

person scorpiozj    schedule 22.02.2012

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")
    }
}
person Andy    schedule 13.03.2017
comment
Хорошее решение, но осторожно, потому что Slider Released вызывается при начале перетаскивания и в конце перетаскивания - person Guy Daher; 10.05.2017
comment
и иногда не называется. Слайдер. Выпущен при выпуске. - person Vadim; 31.07.2019

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

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

person Abo3atef    schedule 11.09.2016

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
  }
}
person Jamie Birch    schedule 13.05.2017

В 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)")
}
person pansora abhay    schedule 22.12.2017

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

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

person zhuoming    schedule 21.12.2017

У меня недавно была аналогичная проблема. Вот что я сделал в 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 делает то, что вы хотите.

person Evdzhan Mustafa    schedule 19.03.2016

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

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);
}
person Raj Subbiah    schedule 22.02.2012
comment
Это отправляет действие каждый раз, когда ползунок перемещается, а не только когда перетаскивание закончилось. - person rob mayoff; 22.02.2012

RxSwift:

self.slider.rx.controlEvent([.touchUpInside, .touchUpOutside])
    .bind(to: self.viewModel.endSlidingSlider)
    .disposed(by: self.disposeBag)
person Adam Smaka    schedule 03.09.2019

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

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

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

person Sameer Jagtap    schedule 15.07.2020