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):
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 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
Dodaj cel dla touchUpInsidei touchUpOutsidewydarzeń. Możesz to zrobić programowo lub z poziomu storyboardu. W ten sposób robisz to programowo
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”.
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)
classSliderExample: UIViewController{
var slider: UISlider = UISlider()
var sliderHasFinishedTracking: Bool = truevar sliderLastStoredValue: Float!overridefuncloadView() {
super.loadView()
slider.minimumValue = 100.0
slider.maximumValue = 200.0
slider.isContinuous = true
slider.value = 100.0self.sliderLastStoredValue = slider.value
slider.addTarget(self, action: #selector(respondToSlideEvents), for: .valueChanged)
// add your slider to the view however you like
}
funcrespondToSlideEvents(sender: UISlider) {
let currentValue: Float = Float(sender.value)
print("Event fired. Current value for slider: \(currentValue)%.")
if(slider.isTracking) {
self.sliderHasFinishedTracking = falseprint("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 = trueprint("Action upon slider drag/tap finishing ⌛️")
}
}
self.sliderLastStoredValue = currentValue
}
}
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ć.
@IBActionfuncactionSlider(_ sender: Any) {
let value = sliderSpeed.value.rounded()
}
Odpowiedzi:
Jeśli nie potrzebujesz żadnych danych pomiędzy przeciąganiem, po prostu ustaw:
[mySlider setContinuous: NO];
W ten sposób
valueChanged
zdarzenie otrzymasz tylko wtedy, gdy użytkownik przestanie przesuwać suwak.Wersja Swift 5 :
mySlider.isContinuous = false
źródło
self.mySlider.isContinuous = false
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.
źródło
isContinuous = true
w swoimUISlider
.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"); }
źródło
Ponieważ
UISlider
jest to podklasaUIControl
, możesz ustawić cel i akcję dla jejUIControlEventTouchUpInside
.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
UIControlEventTouchUpOutside
i dlaUIControlEventTouchCancel
.źródło
UISlider
zmieniło się od czasu napisania tej odpowiedzi.UIControlEventTouchCancel
obsługi w iOS 9. Ale mogę wywołaćUIControlEventTouchUpInside
iUIControlEventTouchUpOutside
tylko.Swift 5 i Swift 4
Dodaj cel dla
touchUpInside
itouchUpOutside
wydarzeń. Możesz to zrobić programowo lub z poziomu storyboardu. W ten sposób robisz to programowoslider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
Napisz swoją funkcję do obsługi końca przeciągania suwaka
func sliderDidEndSliding() { print("end sliding") }
źródło
Możesz użyć:
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
do wykrywania zdarzeń touchDown i touchUp w UISlider
źródło
Myślę, że potrzebujesz zdarzenia kontrolnego
UIControlEventTouchUpInside
.źródło
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") } }
źródło
Połącz
Touch Up Inside
iValue Changed
źródło
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:sliderHasFinishedTracking
isliderLastStoredValue
.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
isTracking
pozostajefalse
)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 } }
źródło
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)") }
źródło
Może powinieneś dodać cel dla zdarzeń UIControlEventTouchUpInside 、 UIControlEventTouchUpOutside 、 UIControlEventTouchCancel.
Spotkałem ten sam problem wcześniej, ponieważ nie dodaję celu dla zdarzenia UIControlEventTouchCancel .
źródło
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.
źródło
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); }
źródło
RxSwift:
self.slider.rx.controlEvent([.touchUpInside, .touchUpOutside]) .bind(to: self.viewModel.endSlidingSlider) .disposed(by: self.disposeBag)
źródło
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() }
źródło