iPhone: Bagaimana cara mendeteksi akhir drag slider?

96

Bagaimana cara mendeteksi acara ketika pengguna telah mengakhiri seret penunjuk penggeser?

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

Jawaban:

180

Jika Anda tidak memerlukan data apa pun di antara seret, Anda cukup menyetel:

[mySlider setContinuous: NO];

Dengan cara ini Anda akan menerima valueChangedacara hanya ketika pengguna berhenti menggerakkan slider.

Versi Swift 5 :

mySlider.isContinuous = false
Rok Jarc
sumber
2
Ini adalah jawaban terbaik untuk pertanyaan ini. Saya berharap kami dapat mengubah jawaban untuk ini.
M.Porooshani
1
i.imgur.com/0Edd2xe.png?1 Xcode versi 6.x memiliki fitur pengaturan setContinuous melalui IDE itu sendiri.
Abhijeet
1
Ya, jawaban terbaik adalah ini.
sabiland
3
Jawaban Hebat. Berikut adalah Kode Swift 4:self.mySlider.isContinuous = false
Marco Weber
2
Ini bukanlah yang diminta oleh penulis. Dia ingin terus meluncur, dan juga ingin tahu kapan harus berhenti.
lbsweek
120

Anda dapat menambahkan tindakan yang membutuhkan dua parameter, pengirim dan peristiwa, untuk UIControlEventValueChanged:

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

Kemudian periksa fase objek sentuh di pawang Anda:

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

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

Catatan di Interface Builder saat menambahkan tindakan, Anda juga memiliki opsi untuk menambahkan parameter pengirim dan peristiwa ke tindakan tersebut.

Devin Pitcher
sumber
1
Bekerja dengan sempurna! Dari mana Anda mendapatkan sumbernya?
Roi Mulia
2
terima kasih @RoiMulia, Saya tidak ingat di mana saya pertama kali melihatnya, saya telah menggunakan slider selama bertahun-tahun. Terkadang saya menggunakannya untuk mengabaikan perubahan pada UITouchPhaseEnded karena nilainya cenderung melonjak saat pengguna mengangkat jari mereka.
Devin Pitcher
2
Ingatlah untuk mengatur isContinuous = truedi Anda UISlider.
krlbsk
2
Ini adalah solusi yang bagus, namun ada masalah dengan pembatalan sentuh. Meskipun ada acara yang "dibatalkan" di enum touchEvent, itu tidak akan diaktifkan saat sentuhan dibatalkan. Oleh karena itu saya merekomendasikan juga menambahkan pendengar untuk acara touchCancel dari Slider. Ini harus mencakup semua kemungkinan.
bnussey
2
Saya melihat bahwa terkadang fase dapat berjalan: dimulai, diam, dipindahkan, tetapi kemudian tidak pernah berakhir atau dibatalkan. Ini bermasalah untuk kasus penggunaan saya karena saya mengharapkan setiap interaksi akan berakhir atau dibatalkan. Perbaikannya dicatat di atas: gunakan target / tindakan pembatalan sentuh yang terpisah.
Jordan H
71

Saya menggunakan notifikasi "Touch Up Inside" dan "Touch up outside".

Pembuat Antarmuka:

Hubungkan kedua notifikasi di Interface Builder ke metode penerimaan Anda. Metodenya bisa seperti ini:

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

Dalam kode:

Jika Anda ingin menyambungkannya secara terprogram, Anda akan memiliki sesuatu seperti ini di viewWillAppear Anda (atau di mana pun itu cocok untuk Anda) panggilan:

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

Metode penerimaan akan terlihat seperti ini:

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

Karena UISlidermerupakan subkelas dari UIControl, Anda dapat menetapkan target dan tindakan untuknya UIControlEventTouchUpInside.

Jika Anda ingin melakukannya dalam kode, tampilannya seperti ini:

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

Itu akan mengirimi Anda dragEndedForSlider:pesan saat sentuhan berakhir.

Jika Anda ingin melakukannya di ujung pena, Anda dapat mengontrol-klik penggeser untuk mendapatkan menu koneksinya, lalu seret dari soket "Touch Up Inside" ke objek target.

Anda juga harus menambahkan target dan tindakan untuk UIControlEventTouchUpOutsidedan untuk UIControlEventTouchCancel.

merampok mayoff
sumber
1
@rob mayoff Maaf, tetapi Anda perlu menggunakan UIControlEventTouchUpOutside. Jika tidak, pemilih tidak akan dipanggil jika jari Anda tidak berada di penggeser setelah Anda selesai menyeret.
pengguna3164248
2
Perilaku UISlidertelah berubah sejak saya menulis jawaban ini.
merampok mayoff
Dapat mengonfirmasi bahwa Anda juga perlu mendaftarkan penangan untuk UIControlEventTouchUpOutside di iOS 9.
lms
Saya tidak pernah bisa memanggil UIControlEventTouchCancelpenangan di iOS 9. Tapi saya bisa memanggil UIControlEventTouchUpInsidedan UIControlEventTouchUpOutsidehanya.
petrsyn
17

Swift 5 dan Swift 4

  1. Tambahkan target untuk touchUpInsidedan touchUpOutsideacara. Anda dapat melakukannya secara terprogram atau dari storyboard. Ini adalah cara Anda melakukannya secara terprogram

    slider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
    
  2. Tuliskan fungsi Anda untuk menangani akhir seret penggeser

    func sliderDidEndSliding() {
        print("end sliding")
    }
    
Guy Daher
sumber
Halo. Bagaimana cara menjeda video saat mulai menyeret?
kemdo
Ini tidak mendeteksi apakah seret pernah terjadi atau tidak, dan dapat dipicu hanya dengan mengetuk tanpa menyeret.
Chewie The Chorkie
9

Kamu bisa memakai:

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

untuk mendeteksi kapan peristiwa touchDown dan touchUp terjadi di UISlider

Mudit Bajpai
sumber
5

Jawaban cepat 3

Saya memiliki masalah yang sama dan akhirnya berhasil, jadi mungkin ini akan membantu seseorang. Hubungkan your_Slider ke 'Value Changed' di storyboard dan ketika slider digerakkan, "Slider Touched" bertindak dan saat melepaskan "Slider Released".

@IBAction func your_Slider(_ sender: UISlider) {
    if (yourSlider.isTracking) {
        print("Slider Touched")
    } else {
        print("Slider Released")
    }
}
Andy
sumber
2
Solusi bagus, tapi hati-hati karena Slider Released dipanggil saat mulai menyeret dan mengakhiri menyeret
Guy Daher
dan terkadang tidak disebut "Slider Released" saat dirilis
Vadim
4

Hubungkan Touch Up InsidedanValue Changed

masukkan deskripsi gambar di sini

Abo3atef
sumber
4

Swift 3.1.0

Terkadang Anda ingin peristiwa seret penggeser diaktifkan terus-menerus, tetapi memiliki opsi untuk menjalankan kode yang berbeda tergantung pada apakah penggeser masih diseret atau baru selesai diseret.

Untuk melakukan ini, saya telah memperluas jawaban Andy di atas yang menggunakan isTrackingproperti slider . Saya perlu mencatat dua status: sliderHasFinishedTrackingdan sliderLastStoredValue.

Kode saya dengan benar:

  • tidak mengaktifkan tindakan saat memulai tarik

  • mengaktifkan tindakan jika pengguna hanya mendorong slider dengan satu ketukan (artinya isTrackingtetap 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
sumber
4

Di Swift 4 Anda dapat menggunakan fungsi ini

1 Langkah pertama: - Menambahkan target di slider

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

2 Langkah kedua: - Membuat fungsi

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

Mungkin Anda harus menambahkan target untuk acara UIControlEventTouchUpInside 、 UIControlEventTouchUpOutside 、 UIControlEventTouchCancel.

Saya bertemu masalah yang sama sebelumnya, karena saya tidak menambahkan target untuk acara UIControlEventTouchCancel .

zhuoming
sumber
1

Saya mengalami masalah serupa baru-baru ini. Inilah yang saya lakukan di Swift:

    theSlider.continuous = false;

Kode yang menyimpan nilai berkelanjutan ini berbunyi:

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

Defaultnya tampaknya YA (benar). Menyetelnya menjadi salah melakukan hal yang Anda inginkan.

Evdzhan Mustafa
sumber
0

Coba seperti ini

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
sumber
Itu mengirimkan tindakan setiap kali ibu jari penggeser bergerak, tidak hanya saat seret telah berakhir.
merampok mayoff
0

RxSwift:

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

Buat tindakan dan outlet untuk slider (atau Anda dapat mengetik pengirim dari tindakan ke UISlider), dan di UI Hapus centang kotak Pembaruan Berkelanjutan. Dengan cara ini kita akan mendapatkan nilai slider hanya ketika slider berhenti menyeret.

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

masukkan deskripsi gambar di sini

Sameer Jagtap
sumber