iPhone: Comment détecter la fin du glissement du curseur?

94

Comment détecter l'événement lorsque l'utilisateur a terminé le glissement d'un curseur de curseur?

DroidHeaven
la source
1
Utilisez: [slider addTarget: auto-action: @selector (sliderStoppedDragging :) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
Henry Sou

Réponses:

171

Si vous n'avez pas besoin de données entre les glissements, vous devez simplement définir:

[mySlider setContinuous: NO];

De cette façon, vous recevrez un valueChangedévénement uniquement lorsque l'utilisateur arrête de déplacer le curseur.

Version Swift 5 :

mySlider.isContinuous = false
Rok Jarc
la source
2
C'est la meilleure réponse à cette question. Je souhaite que nous puissions changer la réponse à cela.
M. Porooshani
1
i.imgur.com/0Edd2xe.png?1 La version 6.x de XCode a cette fonction de paramétrer setContinuous via l'IDE lui-même.
Abhijeet le
1
Oui, la meilleure réponse est celle-ci.
sabiland
1
Xcode 7.3 Interface Builder a des Events [x] Continuous Updatesparamètres pour UISliderView. Décocher cette option est définie continuoussur false / NO.
leanne
3
Très bonne réponse. Voici le code Swift 4:self.mySlider.isContinuous = false
Marco Weber
115

Vous pouvez ajouter une action qui prend deux paramètres, l'expéditeur et un événement, pour UIControlEventValueChanged:

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

Vérifiez ensuite la phase de l'objet tactile dans votre gestionnaire:

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

Remarque dans Interface Builder lors de l'ajout d'une action, vous avez également la possibilité d'ajouter à la fois des paramètres d'expéditeur et d'événement à l'action.

Devin Pitcher
la source
1
Fonctionne parfaitement! Où en avez-vous trouvé la source?
Roi Mulia
2
merci @RoiMulia, je ne me souviens pas où je l'ai vu pour la première fois, j'utilise des curseurs depuis des années. Je l'utilise parfois pour ignorer le changement sur UITouchPhaseEnded car la valeur a tendance à sauter lorsque l'utilisateur lève le doigt.
Devin Pitcher
2
N'oubliez pas de définir isContinuous = truevotre UISlider.
krlbsk
2
C'est une excellente solution, mais il y a un problème avec l'annulation tactile. Bien qu'il y ait un événement "annulé" dans l'énumération touchEvent, il n'est pas déclenché lorsque le toucher est annulé. Par conséquent, je recommande également d'ajouter un écouteur pour l'événement touchCancel à partir du curseur. Cela devrait couvrir toutes les possibilités.
bnussey
2
J'ai vu que parfois la phase peut aller: commencée, stationnaire, déplacée, mais ensuite jamais terminée ni annulée. C'est problématique pour mon cas d'utilisation car je m'attendais à ce que chaque interaction se termine ou soit annulée. Le correctif est noté ci-dessus: utilisez une cible / action d'annulation tactile distincte.
Jordan H le
71

J'utilise les notifications «Retouche à l'intérieur» et «Retouche à l'extérieur».

Constructeur d'interface:

Connectez les deux notifications dans Interface Builder à votre méthode de réception. La méthode pourrait ressembler à ceci:

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

Dans du code:

Si vous voulez le câbler par programme, vous auriez quelque chose comme ça dans votre viewWillAppear (ou partout où cela vous convient) appelez:

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

La méthode de réception ressemblerait à ceci:

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

Puisqu'il UISliders'agit d'une sous-classe de UIControl, vous pouvez définir une cible et une action pour sonUIControlEventTouchUpInside .

Si vous voulez le faire dans le code, cela ressemble à ceci:

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

Cela vous enverra un dragEndedForSlider: message lorsque le toucher se terminera.

Si vous voulez le faire dans votre plume, vous pouvez contrôler-cliquez sur votre curseur pour obtenir son menu de connexions, puis faites-le glisser de la prise «Retouche à l'intérieur» vers l'objet cible.

Vous devez également ajouter une cible et une action pour UIControlEventTouchUpOutsideet pour UIControlEventTouchCancel.

Rob Mayoff
la source
1
@rob mayoff Désolé mais vous devez utiliser UIControlEventTouchUpOutside. Sinon, le sélecteur ne sera pas appelé si votre doigt n'est pas sur le curseur lorsque vous avez terminé de faire glisser.
user3164248
2
Le comportement de UISlidera changé depuis que j'ai écrit cette réponse.
rob mayoff
Peut confirmer que vous avez besoin d'enregistrer également un gestionnaire pour UIControlEventTouchUpOutside dans iOS 9.
lms
Je n'ai jamais pu invoquer le UIControlEventTouchCancelgestionnaire dans iOS 9. Mais je suis capable de l'invoquer UIControlEventTouchUpInsideet UIControlEventTouchUpOutsideuniquement.
petrsyn le
17

Swift 5 et Swift 4

  1. Ajoutez une cible pour touchUpInsideet des touchUpOutsideévénements. Vous pouvez le faire soit par programme, soit à partir du storyboard. Voici comment vous procédez par programme

    slider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
  2. Écrivez votre fonction pour gérer la fin du glissement du curseur

    func sliderDidEndSliding() {
        print("end sliding")
    }
Guy Daher
la source
Bonjour. Comment puis-je mettre la vidéo en pause lorsque je commence à faire glisser?
kemdo le
Cela ne détecte pas si un glissement s'est jamais produit nécessairement, et peut être déclenché simplement en appuyant sans faire glisser.
Chewie The Chorkie
9

Vous pouvez utiliser:

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

pour détecter quand les événements touchDown et touchUp se produisent dans UISlider

Mudit Bajpai
la source
5

Réponse Swift 3

J'ai eu le même problème et j'ai finalement réussi à faire fonctionner cela, alors peut-être que cela aidera quelqu'un. Connectez your_Slider à 'Value Changed' dans le storyboard et lorsque le curseur a bougé "Slider Touched" actionné et quand relâchez "Slider Released".

@IBAction func your_Slider(_ sender: UISlider) {
    if (yourSlider.isTracking) {
        print("Slider Touched")
    } else {
        print("Slider Released")
    }
}
Andy
la source
2
Bonne solution, mais prudent car Slider Released est appelé lorsque vous commencez à glisser et que vous finissez de glisser
Guy Daher
et parfois pas appelé "Slider Released" à la sortie
Vadim
4

Connectez Touch Up InsideetValue Changed

entrez la description de l'image ici

Abo3atef
la source
4

Swift 3.1

Parfois, vous souhaiterez que les événements de glissement du curseur se déclenchent en continu, mais vous avez la possibilité d'exécuter un code différent selon que le curseur est toujours en cours de déplacement ou qu'il vient de finir de le faire.

Pour ce faire, j'ai développé la réponse d'Andy ci-dessus qui utilise la isTrackingpropriété du curseur . J'avais besoin d'enregistrer deux états: sliderHasFinishedTrackingetsliderLastStoredValue .

Mon code correctement:

  • ne déclenche pas d'action au début de la traînée

  • déclenche l'action si l'utilisateur ne déplace le curseur que d'un seul clic (ce qui signifie qu'il isTrackingreste 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
  }
}
Jamie Birch
la source
4

Dans Swift 4, vous pouvez utiliser cette fonction

1 Première étape: - Ajout de la cible dans le curseur

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

2 Deuxième étape: - Créer une fonction

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

Vous devriez peut-être ajouter une cible pour les événements UIControlEventTouchUpInside 、 UIControlEventTouchUpOutside 、 UIControlEventTouchCancel.

J'ai rencontré le même problème avant, car je n'ajoute pas de cible pour l' événement UIControlEventTouchCancel .

zhuoming
la source
1

J'ai eu un problème similaire récemment. Voici ce que j'ai fait dans Swift:

    theSlider.continuous = false;

Le code qui contient cette valeur continue lit:

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

La valeur par défaut semble être OUI (vrai). Le définir sur false fait ce que vous voulez.

Evdzhan Mustafa
la source
0

Essayez comme ça

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);
}
Raj Subbiah
la source
Cela envoie l'action à chaque fois que le pouce du curseur bouge, pas seulement lorsque le glissement est terminé.
rob mayoff
0

RxSwift:

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

Créez une action et une sortie pour le curseur (ou vous pouvez taper l'expéditeur de l'action vers UISlider), et dans l'interface utilisateur, décochez la case Mises à jour continues. De cette façon, nous obtiendrons la valeur du curseur uniquement lorsque le curseur cesse de glisser.

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

entrez la description de l'image ici

Sameer Jagtap
la source