iPhone: come rilevare la fine del trascinamento del cursore?


94

Come rilevare l'evento quando l'utente ha terminato il trascinamento di un cursore a scorrimento?


1
Usa: [slider addTarget: self action: @selector (sliderStoppedDragging :) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
Henry Sou

Risposte:


171

Se non hai bisogno di dati durante il trascinamento, dovresti semplicemente impostare:

[mySlider setContinuous: NO];

In questo modo riceverai l' valueChangedevento solo quando l'utente smette di muovere il cursore.

Versione Swift 5 :

mySlider.isContinuous = false

2
Questa è la migliore risposta a questa domanda. Vorrei che potessimo cambiare la risposta a questo.
M. Porooshani

1
i.imgur.com/0Edd2xe.png?1 XCode versione 6.x ha questa caratteristica di impostare setContinuous tramite l'IDE stesso.
Abhijeet

1
Sì, la migliore risposta è questa.
sabiland

1
Xcode 7.3 Interface Builder ha l' Events [x] Continuous Updatesimpostazione per UISliderView. Deselezionando questa opzione si imposta continuousfalse / NO.
leanne

3
Bella risposta. Ecco il codice Swift 4:self.mySlider.isContinuous = false
Marco Weber

115

Puoi aggiungere un'azione che accetta due parametri, mittente e un evento, per UIControlEventValueChanged:

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

Quindi controlla la fase dell'oggetto touch nel tuo gestore:

- (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 e 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
        }
    }
}

Nota in Interface Builder quando aggiungi un'azione, hai anche la possibilità di aggiungere all'azione i parametri del mittente e dell'evento.


1
Funziona perfettamente! Dove hai preso la fonte per questo?
Roi Mulia

2
grazie @RoiMulia, non ricordo dove l'ho visto la prima volta, lo uso da anni negli slider. A volte lo uso per ignorare la modifica su UITouchPhaseEnded poiché il valore tende a saltare quando l'utente alza il dito.
Devin Pitcher

2
Ricordati di impostare il isContinuous = truetuo file UISlider.
krlbsk

2
Questa è un'ottima soluzione, tuttavia presenta un problema con l'annullamento del tocco. Nonostante sia presente un evento "cancellato" nell'enumerazione touchEvent, non viene attivato quando il tocco viene annullato. Pertanto consiglio anche di aggiungere un listener per l'evento touchCancel dallo Slider. Questo dovrebbe coprire tutte le possibilità.
bnussey

2
Ho visto che a volte la fase può andare: iniziata, ferma, spostata, ma poi mai terminata né annullata. Questo è problematico per il mio caso d'uso poiché mi aspettavo che ogni interazione terminasse o venisse annullata. La correzione è annotata sopra: usa un tocco separato annulla target / azione.
Jordan H

71

Uso le notifiche "Ritocco interno" e "Ritocco esterno".

Costruttore di interfacce:

Collega entrambe le notifiche in Interface Builder al tuo metodo di ricezione. Il metodo potrebbe essere simile a questo:

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

In codice:

Se vuoi collegarlo in modo programmatico, avresti qualcosa di simile nella tua vista WillAppear (o ovunque ti si adatti) chiama:

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

Il metodo di ricezione sarebbe simile a questo:

- (void)sliderDidEndSliding:(NSNotification *)notification {
     NSLog(@"Slider did end sliding... Do your stuff here");
}

19

Poiché UISliderè una sottoclasse di UIControl, puoi impostare un obiettivo e un'azione per il suo UIControlEventTouchUpInside.

Se vuoi farlo in codice, assomiglia a questo:

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

Questo ti invierà un dragEndedForSlider:messaggio quando il tocco finisce.

Se vuoi farlo con il pennino, puoi fare control-clic sul cursore per visualizzare il menu delle connessioni, quindi trascinare dalla presa "Ritocco interno" all'oggetto di destinazione.

Dovresti anche aggiungere un obiettivo e un'azione per UIControlEventTouchUpOutsidee per UIControlEventTouchCancel.


1
@rob mayoff Siamo spiacenti ma è necessario utilizzare UIControlEventTouchUpOutside. In caso contrario, il selettore non verrà chiamato se il dito non è sullo slider al termine del trascinamento.
user3164248

2
Il comportamento di UISliderè cambiato da quando ho scritto questa risposta.
Rob Mayoff

Può confermare che non c'è bisogno di registrare anche un gestore per UIControlEventTouchUpOutside in iOS 9.
LMS

Non sono mai stato in grado di invocare il UIControlEventTouchCancelgestore in iOS 9. Ma sono in grado di invocare UIControlEventTouchUpInsidee UIControlEventTouchUpOutsidesolo.
petrsyn

17

Swift 5 e Swift 4

  1. Aggiungi target per touchUpInsideed touchUpOutsideeventi. Puoi farlo in modo programmatico o dallo storyboard. Ecco come lo fai in modo programmatico

    slider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
  2. Scrivi la tua funzione per gestire la fine del trascinamento del cursore

    func sliderDidEndSliding() {
        print("end sliding")
    }
    

Ciao. Come posso mettere in pausa il video quando inizio a trascinare?
kemdo

Questo non rileva se si è mai verificato necessariamente un trascinamento e può essere attivato semplicemente toccando senza trascinare.
Chewie The Chorkie

9

Puoi usare:

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

per rilevare quando si verificano gli eventi touchDown e touchUp in UISlider



5

Risposta rapida 3

Ho avuto lo stesso problema e alla fine è riuscito a far funzionare tutto, quindi forse aiuterà qualcuno. Collega il tuo_Slider a "Valore modificato" nello storyboard e quando lo slider si sposta "Slider Touched" azionato e quando lascialo "Slider rilasciato".

@IBAction func your_Slider(_ sender: UISlider) {
    if (yourSlider.isTracking) {
        print("Slider Touched")
    } else {
        print("Slider Released")
    }
}

2
Buona soluzione, ma attenzione perché Slider Rilasciato viene chiamato quando inizia il trascinamento e termina il trascinamento
Guy Daher

e talvolta non viene chiamato "Slider rilasciato" al momento del rilascio
Vadim


4

Swift 3.1

A volte potresti volere che gli eventi di trascinamento del cursore si attivino continuamente, ma hai la possibilità di eseguire un codice diverso a seconda che il cursore sia ancora trascinato o che sia appena stato trascinato.

Per fare ciò, ho ampliato la risposta di Andy sopra che utilizza la isTrackingproprietà del cursore . Avevo bisogno di registrare due stati: sliderHasFinishedTrackinge sliderLastStoredValue.

Il mio codice correttamente:

  • non attiva un'azione all'avvio del trascinamento

  • attiva l'azione se l'utente spinge il cursore con un solo tocco (il che significa che isTrackingrimane 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

In Swift 4 puoi usare questa funzione

1 Primo passo: - Aggiunta del bersaglio nel cursore

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

2 Secondo passo: - Creare una funzione

@objc func sliderDidEndSliding(notification: NSNotification)
{
   print("Hello-->\(distanceSlider.value)")
}

2

Forse dovresti aggiungere il target per gli eventi UIControlEventTouchUpInside 、 UIControlEventTouchUpOutside 、 UIControlEventTouchCancel.

Ho incontrato lo stesso problema prima, perché non aggiungo target per l' evento UIControlEventTouchCancel .


1

Ho avuto un problema simile di recente. Ecco cosa ho fatto in Swift:

    theSlider.continuous = false;

Il codice che contiene questo valore continuo legge:

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

L'impostazione predefinita sembra essere YES (true). Impostarlo su false fa la cosa che desideri.


0

Prova in questo modo

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);
}

Questo invia l'azione ogni volta che il pollice del cursore si sposta, non solo quando il trascinamento è terminato.
Rob Mayoff il

0

RxSwift:

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

0

Crea un'azione e uno sbocco per il dispositivo di scorrimento (oppure puoi digitare il mittente del cast da azione a UISlider) e nell'interfaccia utente deseleziona la casella di controllo Aggiornamenti continui. In questo modo otterremo il valore dello slider solo quando lo slider smette di trascinare.

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

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.