iPhone: Wie erkennt man das Ende des Schiebereglers?

93

Wie erkenne ich das Ereignis, wenn der Benutzer das Ziehen eines Schiebereglers beendet hat?

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

Antworten:

170

Wenn Sie zwischen dem Ziehen keine Daten benötigen, sollten Sie einfach Folgendes festlegen:

[mySlider setContinuous: NO];

Auf diese Weise erhalten Sie nur dann ein valueChangedEreignis, wenn der Benutzer den Schieberegler nicht mehr bewegt.

Swift 5 Version:

mySlider.isContinuous = false
Rok Jarc
quelle
2
Dies ist die beste Antwort auf diese Frage. Ich wünschte, wir könnten die Antwort darauf ändern.
M. Porooshani
1
i.imgur.com/0Edd2xe.png?1 XCode Version 6.x verfügt über diese Funktion zum Festlegen von setContinuous über die IDE selbst.
Abhijeet
1
Ja, die beste Antwort ist dies.
Sabiland
1
Xcode 7.3 Interface Builder hat Events [x] Continuous UpdatesEinstellungen für UISliderView. Wenn Sie dieses Kontrollkästchen deaktivieren continuous, wird false / NO festgelegt.
Leanne
3
Gute Antwort. Hier ist der Swift 4 Code:self.mySlider.isContinuous = false
Marco Weber
113

Sie können für UIControlEventValueChanged eine Aktion hinzufügen, die zwei Parameter akzeptiert: Absender und Ereignis:

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

Überprüfen Sie dann die Phase des Touch-Objekts in Ihrem Handler:

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

Schnelle 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
        }
    }
}

Beachten Sie, dass Sie im Interface Builder beim Hinzufügen einer Aktion auch die Option haben, der Aktion sowohl Absender- als auch Ereignisparameter hinzuzufügen.

Devin Pitcher
quelle
1
Funktioniert perfekt! Woher hast du die Quelle dafür?
Roi Mulia
2
danke @RoiMulia, ich erinnere mich nicht, wo ich es zum ersten Mal gesehen habe, ich benutze es seit Jahren in Schiebereglern. Ich benutze es manchmal, um die Änderung an UITouchPhaseEnded zu ignorieren, da der Wert dazu neigt, zu springen, wenn der Benutzer seinen Finger hebt.
Devin Pitcher
2
Denken Sie daran, isContinuous = truein Ihrem zu setzen UISlider.
krlbsk
2
Dies ist eine großartige Lösung, es gibt jedoch ein Problem mit dem Abbrechen von Berührungen. Obwohl in der touchEvent-Enumeration ein "abgebrochenes" Ereignis vorhanden ist, wird es nicht ausgelöst, wenn die Berührung abgebrochen wird. Daher empfehle ich, auch einen Listener für das touchCancel-Ereignis über den Slider hinzuzufügen. Dies sollte alle Möglichkeiten abdecken.
Bnussey
2
Ich habe gesehen, dass manchmal die Phase verlaufen kann: begonnen, stationär, bewegt, aber dann nie beendet oder abgebrochen. Dies ist für meinen Anwendungsfall problematisch, da ich erwartet habe, dass jede Interaktion beendet oder abgebrochen wird. Das Update wurde oben erwähnt: Verwenden Sie ein separates Ziel / eine Aktion zum Abbrechen von Berührungen.
Jordan H
71

Ich verwende die Benachrichtigungen "Touch Up Inside" und "Touch Up Outside".

Interface Builder:

Verbinden Sie beide Benachrichtigungen im Interface Builder mit Ihrer Empfangsmethode. Die Methode könnte folgendermaßen aussehen:

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

In Code:

Wenn Sie es programmgesteuert verkabeln möchten, haben Sie so etwas in Ihrem viewWillAppear-Aufruf (oder wo immer es Ihnen passt):

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

Die Empfangsmethode würde folgendermaßen aussehen:

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

Da UISlideres sich um eine Unterklasse von handelt UIControl, können Sie ein Ziel und eine Aktion für seine festlegen UIControlEventTouchUpInside.

Wenn Sie es in Code tun möchten, sieht es so aus:

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

Das wird Ihnen eine dragEndedForSlider:Nachricht senden, wenn die Berührung endet.

Wenn Sie dies in Ihrer Feder tun möchten, können Sie bei gedrückter Ctrl-Taste auf Ihren Schieberegler klicken, um das Verbindungsmenü aufzurufen, und dann vom Sockel „Touch Up Inside“ zum Zielobjekt ziehen.

Sie sollten auch ein Ziel und eine Aktion für UIControlEventTouchUpOutsideund für hinzufügen UIControlEventTouchCancel.

Rob Mayoff
quelle
1
@rob mayoff Entschuldigung, aber Sie müssen UIControlEventTouchUpOutside verwenden. Andernfalls wird der Selektor nicht aufgerufen, wenn sich Ihr Finger nach dem Ziehen nicht auf dem Schieberegler befindet.
user3164248
2
Das Verhalten von UISliderhat sich geändert, seit ich diese Antwort geschrieben habe.
Rob Mayoff
Kann bestätigen , dass Sie es auch brauchen , um einen Handler für UIControlEventTouchUpOutside in iOS registrieren 9.
lms
Ich war nie aufrufen können UIControlEventTouchCancel9. in iOS - Handler Aber ich bin in der Lage zu berufen UIControlEventTouchUpInsideund UIControlEventTouchUpOutsidenur.
Petrsyn
16

Swift 5 und Swift 4

  1. Ziel für touchUpInsideund touchUpOutsideEreignisse hinzufügen. Sie können dies entweder programmgesteuert oder über das Storyboard tun. So machen Sie es programmatisch

    slider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
  2. Schreiben Sie Ihre Funktion, um das Ende des Schiebereglers zu bewältigen

    func sliderDidEndSliding() {
        print("end sliding")
    }
Guy Daher
quelle
Hallo. Wie kann ich das Video anhalten, wenn ich mit dem Ziehen beginne?
Kemdo
Dies erkennt nicht, ob jemals ein Ziehen stattgefunden hat oder nicht, und kann durch einfaches Tippen ohne Ziehen ausgelöst werden.
Chewie The Chorkie
9

Sie können verwenden:

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

um zu erkennen, wann die Ereignisse touchDown und touchUp in UISlider auftreten

Mudit Bajpai
quelle
5

Schnelle 3 Antwort

Ich hatte das gleiche Problem und brachte es schließlich zum Laufen, also hilft es vielleicht jemandem. Verbinden Sie Ihren_Slider mit 'Wert geändert' im Storyboard und wenn der Schieberegler bewegt wird, wird "Schieberegler berührt" aktiviert und wenn "Schieberegler freigegeben" losgelassen wird.

@IBAction func your_Slider(_ sender: UISlider) {
    if (yourSlider.isTracking) {
        print("Slider Touched")
    } else {
        print("Slider Released")
    }
}
Andy
quelle
2
Gute Lösung, aber vorsichtig, da Slider Released aufgerufen wird, wenn mit dem Ziehen begonnen und das Ziehen beendet wird
Guy Daher
und manchmal nicht "Slider Released" bei Veröffentlichung genannt
Vadim
4

Verbinden Touch Up InsideundValue Changed

Geben Sie hier die Bildbeschreibung ein

Abo3atef
quelle
4

Swift 3.1

Manchmal möchten Sie, dass die Drag-Ereignisse des Schiebereglers kontinuierlich ausgelöst werden, haben jedoch die Möglichkeit, unterschiedlichen Code auszuführen, je nachdem, ob der Slider noch gezogen wird oder gerade nicht mehr gezogen wurde.

Zu diesem Zweck habe ich die obige Antwort von Andy erweitert, die die isTrackingEigenschaft des Schiebereglers nutzt . Ich musste zwei Zustände aufzeichnen: sliderHasFinishedTrackingund sliderLastStoredValue.

Mein Code richtig:

  • Löst beim Starten des Ziehens keine Aktion aus

  • Löst die Aktion aus, wenn der Benutzer den Schieberegler nur mit einem einzigen Tastendruck anstößt (was bedeutet, dass dies isTrackingverbleibt 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
quelle
4

In Swift 4 können Sie diese Funktion verwenden

1 Frist-Schritt: - Hinzufügen des Ziels im Schieberegler

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

2 Zweiter Schritt: - Erstellen Sie eine Funktion

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

Möglicherweise sollten Sie ein Ziel für UIControlEventTouchUpInside 、 UIControlEventTouchUpOutside 、 UIControlEventTouchCancel-Ereignisse hinzufügen.

Ich bin zuvor auf dasselbe Problem gestoßen , weil ich kein Ziel für das UIControlEventTouchCancel- Ereignis hinzugefügt habe .

zhuoming
quelle
1

Ich hatte kürzlich ein ähnliches Problem. Folgendes habe ich in Swift getan:

    theSlider.continuous = false;

Der Code, der diesen fortlaufenden Wert enthält, lautet:

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

Der Standardwert scheint JA (wahr) zu sein. Wenn Sie es auf false setzen, tun Sie genau das, was Sie wollen.

Evdzhan Mustafa
quelle
0

Versuchen Sie es so

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
quelle
Dadurch wird die Aktion jedes Mal gesendet, wenn sich der Daumen des Schiebereglers bewegt, nicht nur, wenn das Ziehen beendet ist.
Rob Mayoff
0

RxSwift:

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

Erstellen Sie eine Aktion und einen Ausgang für den Schieberegler (oder geben Sie den Absender von der Aktion in UISlider ein), und deaktivieren Sie in der Benutzeroberfläche das Kontrollkästchen Kontinuierliche Updates. Auf diese Weise erhalten wir den Schiebereglerwert nur, wenn der Schieberegler nicht mehr gezogen wird.

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

Geben Sie hier die Bildbeschreibung ein

Sameer Jagtap
quelle