iPhone : Как да открия края на плъзгането на плъзгача?

Как да открием събитието, когато потребителят е прекратил плъзгането на показалец на плъзгач?


person DroidHeaven    schedule 22.02.2012    source източник
comment
Използвайте: [slider addTarget:self action:@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
В този случай оставяте непрекъснатото свойство на YES - състояние по подразбиране. - 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;
    }
}

Суифт 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
        }
    }
}

Забележете, че в Interface Builder, когато добавяте действие, вие също имате опцията да добавите към действието параметри на изпращача и събитието.

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 case ще се извиква непрекъснато (т.е. много пъти) в главната нишка, докато позицията на плъзгача се актуализира. Така че не искате да извършвате интензивна работа с процесор или I/O в кутията .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 , repeats: 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

Използвам известията „Ретуширане отвътре“ и „Ретуширане отвън“.

Конструктор на интерфейс:

Свържете двете известия в Interface Builder с вашия метод на получаване. Методът може да изглежда така:

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

В код:

Ако искате да го свържете програмно, ще имате нещо подобно във вашия viewWillAppear (или където ви е удобно) call:

[_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:, когато докосването приключи.

Ако искате да го направите в перото си, можете да щракнете върху плъзгача, за да получите менюто за връзки, и след това да плъзнете от гнездото „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

Имах същия проблем и в крайна сметка го накарах, така че може би ще помогне на някого. Свържете вашия_плъзгач към „Променена стойност“ в сценария и когато плъзгачът се премести, „Плъзгачът е докоснат“ действа, а когато го пуснете, „Плъзгачът е освободен“.

@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
и понякога не се нарича Slider Released on release - 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