iPhone: Jak wykryć koniec przeciągania suwaka?

96

Jak wykryć zdarzenie, gdy użytkownik zakończył przeciąganie wskaźnika suwaka?

DroidHeaven
źródło
1
Użyj: [slider addTarget: self action: @selector (sliderStoppedDragging :) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
Henry Sou

Odpowiedzi:

180

Jeśli nie potrzebujesz żadnych danych pomiędzy przeciąganiem, po prostu ustaw:

[mySlider setContinuous: NO];

W ten sposób valueChangedzdarzenie otrzymasz tylko wtedy, gdy użytkownik przestanie przesuwać suwak.

Wersja Swift 5 :

mySlider.isContinuous = false
Rok Jarc
źródło
2
To najlepsza odpowiedź na to pytanie. Chciałbym, żebyśmy mogli zmienić odpowiedź na to.
M. Porooshani,
1
i.imgur.com/0Edd2xe.png?1 XCode w wersji 6.x ma tę funkcję ustawiania setContinuous przez samo IDE.
Abhijeet
1
Tak, najlepsza odpowiedź brzmi:
sabiland
3
Świetna odpowiedź. Oto kod Swift 4:self.mySlider.isContinuous = false
Marco Weber
2
Nie o to prosi autor. Chce ciągle się ślizgać, a także chce wiedzieć, kiedy przestać.
lbsweek,
120

Możesz dodać akcję, która przyjmuje dwa parametry, nadawcę i zdarzenie, dla UIControlEventValueChanged:

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

Następnie sprawdź fazę obiektu dotykowego w twoim programie obsługi:

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

Uwaga w programie Interface Builder podczas dodawania akcji można również dodać do akcji parametry nadawcy i zdarzenia.

Devin Pitcher
źródło
1
Działa świetnie! Skąd masz to źródło?
Roi Mulia
2
dzięki @RoiMulia, nie pamiętam, gdzie po raz pierwszy to zobaczyłem, od lat używam suwaków. Czasami używam go, aby zignorować zmianę w UITouchPhaseEnded, ponieważ wartość ma tendencję do przeskakiwania, gdy użytkownik podnosi palec.
Devin Pitcher
2
Pamiętaj, aby ustawić isContinuous = truew swoim UISlider.
krlbsk
2
To świetne rozwiązanie, ale ma problem z anulowaniem dotykowym. Mimo że w wyliczeniu touchEvent występuje zdarzenie „cancelled”, nie jest ono uruchamiane po anulowaniu dotknięcia. Dlatego zalecam również dodanie nasłuchiwania zdarzenia touchCancel z poziomu Slidera. Powinno to obejmować wszystkie możliwości.
bnussey
2
Widziałem, że czasami faza może iść: rozpoczęta, nieruchoma, przesunięta, ale potem nigdy się nie skończyła ani nie została anulowana. Jest to problematyczne w moim przypadku użycia, ponieważ spodziewałem się zakończenia lub anulowania każdej interakcji. Poprawka jest zaznaczona powyżej: użyj oddzielnego celu / akcji anulowania dotykowego.
Jordan H
71

Korzystam z powiadomień „Retusz wewnątrz” i „Poprawianie na zewnątrz”.

Konstruktor interfejsu:

Połącz oba powiadomienia w Interface Builder z metodą odbierania. Metoda mogłaby wyglądać następująco:

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

W kodzie:

Jeśli chcesz podłączyć to programowo, powinieneś mieć coś takiego w swoim wywołaniu viewWillAppear (lub gdziekolwiek to pasuje):

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

Sposób odbioru wyglądałby następująco:

- (void)sliderDidEndSliding:(NSNotification *)notification {
     NSLog(@"Slider did end sliding... Do your stuff here");
}
Tomasz
źródło
19

Ponieważ UISliderjest to podklasa UIControl, możesz ustawić cel i akcję dla jej UIControlEventTouchUpInside.

Jeśli chcesz to zrobić w kodzie, wygląda to tak:

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

To wyśle ​​ci dragEndedForSlider:wiadomość po zakończeniu dotknięcia.

Jeśli chcesz to zrobić w końcówce, możesz kliknąć suwak z wciśniętym klawiszem Control, aby wyświetlić menu połączeń, a następnie przeciągnąć z gniazda „Touch Up Inside” do obiektu docelowego.

Powinieneś także dodać cel i akcję dla UIControlEventTouchUpOutsidei dla UIControlEventTouchCancel.

rob mayoff
źródło
1
@rob mayoff Przepraszamy, ale musisz użyć UIControlEventTouchUpOutside. W przeciwnym razie selektor nie zostanie wywołany, jeśli po zakończeniu przeciągania palec nie znajdzie się na suwaku.
user3164248
2
Zachowanie UISliderzmieniło się od czasu napisania tej odpowiedzi.
rob mayoff
Może potwierdzić, że nie trzeba również zarejestrować obsługi dla UIControlEventTouchUpOutside w iOS 9.
LMS
Nigdy nie byłem w stanie wywołać programu UIControlEventTouchCancelobsługi w iOS 9. Ale mogę wywołać UIControlEventTouchUpInsidei UIControlEventTouchUpOutsidetylko.
petrsyn
17

Swift 5 i Swift 4

  1. Dodaj cel dla touchUpInsidei touchUpOutsidewydarzeń. Możesz to zrobić programowo lub z poziomu storyboardu. W ten sposób robisz to programowo

    slider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
    
  2. Napisz swoją funkcję do obsługi końca przeciągania suwaka

    func sliderDidEndSliding() {
        print("end sliding")
    }
    
Guy Daher
źródło
Witaj. Jak mogę wstrzymać wideo po rozpoczęciu przeciągania?
kemdo
To nie wykrywa, czy przeciągnięcie kiedykolwiek miało miejsce, czy nie, i może zostać wywołane przez proste dotknięcie bez przeciągania.
Chewie The Chorkie
9

Możesz użyć:

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

do wykrywania zdarzeń touchDown i touchUp w UISlider

Mudit Bajpai
źródło
5

Szybka 3 odpowiedź

Miałem ten sam problem iw końcu udało mi się to zadziałać, więc może to komuś pomoże. Połącz your_Slider z „Zmieniono wartość” w scenorysie, a gdy suwak zostanie przesunięty, „Dotykany suwak” zadziała, a po puszczeniu „Zwolniony suwak”.

@IBAction func your_Slider(_ sender: UISlider) {
    if (yourSlider.isTracking) {
        print("Slider Touched")
    } else {
        print("Slider Released")
    }
}
Andy
źródło
2
Dobre rozwiązanie, ale ostrożne, ponieważ Slider Released jest wywoływany podczas rozpoczynania i kończenia przeciągania
Guy Daher
i czasami nie nazywa się „Slider Released” w
Vadim
4

Połącz Touch Up InsideiValue Changed

wprowadź opis obrazu tutaj

Abo3atef
źródło
4

Swift 3.1

Czasami chcesz, aby zdarzenia przeciągania suwaka były uruchamiane w sposób ciągły, ale masz możliwość wykonania innego kodu w zależności od tego, czy suwak jest nadal przeciągany, czy właśnie zakończył przeciąganie.

Aby to zrobić, rozszerzyłem powyższą odpowiedź Andy'ego, która wykorzystuje właściwość suwaka isTracking. Musiałem nagrać dwa stany: sliderHasFinishedTrackingisliderLastStoredValue .

Mój kod poprawnie:

  • nie uruchamia akcji po rozpoczęciu przeciągania

  • uruchamia akcję, jeśli użytkownik tylko przesuwa suwak jednym dotknięciem (co oznacza, że isTrackingpozostaje 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
źródło
4

W Swift 4 możesz użyć tej funkcji

1 Pierwszy krok: - Dodanie celu w suwaku

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

2 Drugi krok: - Utwórz funkcję

@objc func sliderDidEndSliding(notification: NSNotification)
{
   print("Hello-->\(distanceSlider.value)")
}
pansora abhay
źródło
2

Może powinieneś dodać cel dla zdarzeń UIControlEventTouchUpInside 、 UIControlEventTouchUpOutside 、 UIControlEventTouchCancel.

Spotkałem ten sam problem wcześniej, ponieważ nie dodaję celu dla zdarzenia UIControlEventTouchCancel .

zhuoming
źródło
1

Niedawno miałem podobny problem. Oto, co zrobiłem w Swift:

    theSlider.continuous = false;

Kod, który przechowuje tę ciągłą wartość, czyta:

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

Domyślną wartością wydaje się TAK (prawda). Ustawienie wartości false robi to, czego chcesz.

Evdzhan Mustafa
źródło
0

Spróbuj w ten sposób

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
źródło
To wysyła akcję za każdym razem, gdy przesuwa się kciuk suwaka, a nie tylko po zakończeniu przeciągania.
rob mayoff
0

RxSwift:

self.slider.rx.controlEvent([.touchUpInside, .touchUpOutside])
    .bind(to: self.viewModel.endSlidingSlider)
    .disposed(by: self.disposeBag)
Adam Smaka
źródło
0

Utwórz akcję i wylot dla suwaka (lub możesz wysłać nadawcę z akcji do UISlider) i w interfejsie użytkownika usuń zaznaczenie pola wyboru Ciągłe aktualizacje. W ten sposób wartość suwaka uzyskamy tylko wtedy, gdy suwak przestanie się przeciągać.

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

wprowadź opis obrazu tutaj

Sameer Jagtap
źródło