iPhone: จะตรวจจับจุดสิ้นสุดของการลากแถบเลื่อนได้อย่างไร?


96

จะตรวจจับเหตุการณ์ได้อย่างไรเมื่อผู้ใช้สิ้นสุดการลากตัวชี้ตัวเลื่อน


1
ใช้: [slider addTarget: self action: @selector (sliderStoppedDragging :) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
Henry Sou

คำตอบ:


180

หากคุณไม่ต้องการข้อมูลใด ๆ ระหว่างการลากมากกว่าที่คุณควรตั้งค่า:

[mySlider setContinuous: NO];

วิธีนี้คุณจะได้รับvalueChangedเหตุการณ์เมื่อผู้ใช้หยุดเลื่อนแถบเลื่อนเท่านั้น

เวอร์ชันSwift 5 :

mySlider.isContinuous = false

2
นี่คือคำตอบที่ดีที่สุดสำหรับคำถามนี้ ฉันหวังว่าเราจะเปลี่ยนคำตอบของสิ่งนี้ได้
M. Porooshani

1
i.imgur.com/0Edd2xe.png?1 XCode เวอร์ชัน 6.x มีคุณสมบัติของการตั้งค่า setContinuous ผ่าน IDE เอง
Abhijeet

1
ใช่คำตอบที่ดีที่สุดคือสิ่งนี้
sabiland

3
คำตอบที่ดี นี่คือรหัส Swift 4:self.mySlider.isContinuous = false
Marco Weber

2
นี่ไม่ใช่สิ่งที่ผู้เขียนกำลังถาม เขาต้องการสไลด์อย่างต่อเนื่องและต้องการทราบว่าเมื่อใดควรหยุด
lbsweek

120

คุณสามารถเพิ่มการดำเนินการที่รับสองพารามิเตอร์ผู้ส่งและเหตุการณ์สำหรับ UIControlEventValueChanged:

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

จากนั้นตรวจสอบเฟสของวัตถุสัมผัสในตัวจัดการของคุณ:

- (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 และ 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
        }
    }
}

หมายเหตุใน Interface Builder เมื่อเพิ่มการดำเนินการคุณยังมีตัวเลือกในการเพิ่มพารามิเตอร์ผู้ส่งและเหตุการณ์ให้กับการดำเนินการ


1
ทำงานได้อย่างสมบูรณ์แบบ! คุณได้แหล่งที่มาของสิ่งนั้นมาจากไหน?
Roi Mulia

2
ขอบคุณ @RoiMulia ฉันจำไม่ได้ว่าฉันเห็นมันครั้งแรกที่ไหนฉันใช้สไลเดอร์มาหลายปีแล้ว บางครั้งฉันใช้มันเพื่อเพิกเฉยต่อการเปลี่ยนแปลงใน UITouchPhaseEnded เนื่องจากค่ามีแนวโน้มที่จะกระโดดเมื่อผู้ใช้ยกนิ้วขึ้น
Devin Pitcher

2
อย่าลืมตั้งค่าisContinuous = trueในUISliderไฟล์.
krlbsk

2
นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยม แต่มีปัญหาในการยกเลิกการสัมผัส แม้จะมีเหตุการณ์ "ยกเลิก" ใน touchEvent enum แต่ก็ไม่เริ่มทำงานเมื่อการสัมผัสถูกยกเลิก ดังนั้นฉันขอแนะนำให้เพิ่ม Listener สำหรับเหตุการณ์ touchCancel จาก Slider ด้วย สิ่งนี้ควรครอบคลุมความเป็นไปได้ทั้งหมด
bnussey

2
ฉันเห็นว่าบางครั้งขั้นตอนสามารถไปได้: เริ่มหยุดนิ่งเคลื่อนไหว แต่แล้วก็ไม่สิ้นสุดหรือยกเลิก นี่เป็นปัญหาสำหรับกรณีการใช้งานของฉันเนื่องจากฉันคาดว่าทุกการโต้ตอบจะสิ้นสุดหรือถูกยกเลิก การแก้ไขมีการระบุไว้ข้างต้น: ใช้เป้าหมาย / การดำเนินการยกเลิกการสัมผัสแยกกัน
Jordan H

71

ฉันใช้การแจ้งเตือน "Touch Up Inside" และ "Touch up outside"

ตัวสร้างอินเทอร์เฟซ:

เชื่อมต่อการแจ้งเตือนทั้งสองในตัวสร้างอินเทอร์เฟซกับวิธีการรับของคุณ วิธีการอาจมีลักษณะดังนี้:

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

ในรหัส:

หากคุณต้องการวางสายโดยใช้โปรแกรมคุณจะมีสิ่งนี้ใน viewWillAppear (หรือที่ใดก็ตามที่เหมาะกับคุณ) โทร:

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

วิธีการรับจะมีลักษณะดังนี้:

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

19

ตั้งแต่UISliderเป็น subclass ของคุณสามารถตั้งค่าเป้าหมายและการดำเนินการของUIControlUIControlEventTouchUpInside

หากคุณต้องการทำในรหัสจะมีลักษณะดังนี้:

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

ซึ่งจะส่งdragEndedForSlider:ข้อความถึงคุณเมื่อการสัมผัสสิ้นสุดลง

หากคุณต้องการทำในปลายปากกาคุณสามารถควบคุมแล้วคลิกแถบเลื่อนเพื่อรับเมนูการเชื่อมต่อจากนั้นลากจากซ็อกเก็ต“ Touch Up Inside” ไปยังวัตถุเป้าหมาย

นอกจากนี้คุณควรเพิ่มเป้าหมายและการดำเนินการและUIControlEventTouchUpOutsideUIControlEventTouchCancel


1
@rob mayoff ขออภัยคุณจำเป็นต้องใช้ UIControlEventTouchUpOutside มิฉะนั้นตัวเลือกจะไม่ถูกเรียกหากนิ้วของคุณไม่อยู่บนแถบเลื่อนเมื่อคุณลากเสร็จ
user3164248

2
พฤติกรรมของUISliderฉันเปลี่ยนไปตั้งแต่ฉันเขียนคำตอบนี้
rob mayoff

สามารถยืนยันได้ว่าคุณจะต้องมีการลงทะเบียนจัดการสำหรับ UIControlEventTouchUpOutside ใน iOS 9
LMS

ผมก็ไม่สามารถที่จะก่อให้เกิดUIControlEventTouchCancelการจัดการใน iOS 9. แต่ฉันสามารถที่จะเรียกใช้UIControlEventTouchUpInsideและUIControlEventTouchUpOutsideเพียง
petrsyn

17

Swift 5 และ Swift 4

  1. เพิ่มเป้าหมายtouchUpInsideและtouchUpOutsideเหตุการณ์ คุณสามารถทำได้ทั้งแบบเป็นโปรแกรมหรือจากสตอรีบอร์ด นี่คือวิธีที่คุณทำโดยใช้โปรแกรม

    slider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
    
  2. เขียนฟังก์ชันของคุณเพื่อจัดการกับจุดสิ้นสุดของการลากแถบเลื่อน

    func sliderDidEndSliding() {
        print("end sliding")
    }
    

สวัสดี. ฉันจะหยุดวิดีโอชั่วคราวเมื่อเริ่มลากได้อย่างไร
kemdo

สิ่งนี้ตรวจไม่พบว่าจำเป็นต้องมีการลากหรือไม่และสามารถเรียกใช้งานได้โดยการแตะโดยไม่ต้องลาก
Chewie The Chorkie

9

คุณสามารถใช้ได้:

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

เพื่อตรวจจับเมื่อเหตุการณ์ touchDown และ touchUp เกิดขึ้นใน UISlider



5

คำตอบ Swift 3

ฉันมีปัญหาเดียวกันและในที่สุดก็ใช้งานได้ดังนั้นมันอาจจะช่วยใครสักคนได้ เชื่อมต่อ your_Slider กับ 'Value Changed' ในสตอรีบอร์ดและเมื่อเลื่อนตัวเลื่อน "Slider Touched" ที่ดำเนินการและเมื่อปล่อย "Slider Released"

@IBAction func your_Slider(_ sender: UISlider) {
    if (yourSlider.isTracking) {
        print("Slider Touched")
    } else {
        print("Slider Released")
    }
}

2
ทางออกที่ดี แต่ระวังเพราะ Slider Released ถูกเรียกเมื่อเริ่มลากและสิ้นสุดการลาก
Guy Daher

และบางครั้งจะไม่เรียกว่า "Slider Released" เมื่อวางจำหน่าย
Vadim


4

Swift 3.1

บางครั้งคุณอาจต้องการให้เหตุการณ์การลากของตัวเลื่อนเริ่มทำงานอย่างต่อเนื่อง แต่มีตัวเลือกในการเรียกใช้โค้ดที่แตกต่างกันขึ้นอยู่กับว่าแถบเลื่อนยังคงถูกลากอยู่หรือเพิ่งเสร็จสิ้นการลาก

ในการทำเช่นนี้ฉันได้ขยายคำตอบของ Andy ข้างต้นซึ่งใช้ประโยชน์จากisTrackingคุณสมบัติของแถบเลื่อน ฉันต้องการบันทึกสองสถานะ: sliderHasFinishedTrackingและsliderLastStoredValue.

รหัสของฉันถูกต้อง:

  • ไม่เริ่มการกระทำเมื่อเริ่มการลาก

  • เริ่มการทำงานหากผู้ใช้เพียงแค่ขยับตัวเลื่อนด้วยการแตะเพียงครั้งเดียว (หมายความว่าisTrackingยังคงอยู่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
  }
}

4

ใน Swift 4 คุณสามารถใช้ฟังก์ชันนี้ได้

1 Frist step: - การเพิ่มเป้าหมายในแถบเลื่อน

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

2 ขั้นตอนที่สอง: - สร้างฟังก์ชัน

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

2

บางทีคุณควรเพิ่มเป้าหมายสำหรับเหตุการณ์ UIControlEventTouchUpInside、 UIControlEventTouchUpOutside、 UIControlEventTouchCancel

ฉันพบปัญหาเดียวกันมาก่อนเพราะฉันไม่ได้เพิ่มเป้าหมายสำหรับเหตุการณ์UIControlEventTouchCancel


1

ฉันมีปัญหาคล้ายกันเมื่อเร็ว ๆ นี้ นี่คือสิ่งที่ฉันทำใน Swift:

    theSlider.continuous = false;

รหัสที่เก็บค่าต่อเนื่องนี้อ่าน:

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

ค่าเริ่มต้นดูเหมือนจะเป็นใช่ (จริง) การตั้งค่าเป็นเท็จจะทำสิ่งที่คุณต้องการ


0

ลองแบบนี้ดูสิ

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

ซึ่งจะส่งการกระทำทุกครั้งที่นิ้วหัวแม่มือของตัวเลื่อนขยับไม่ใช่แค่เมื่อการลากสิ้นสุดลง
rob mayoff


0

สร้างการดำเนินการและทางออกสำหรับแถบเลื่อน (หรือคุณสามารถพิมพ์ผู้ส่งจากการดำเนินการไปยัง UISlider) และใน UI ยกเลิกการเลือกช่องทำเครื่องหมายการอัปเดตอย่างต่อเนื่อง วิธีนี้เราจะได้ค่าตัวเลื่อนก็ต่อเมื่อตัวเลื่อนหยุดลาก

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

ป้อนคำอธิบายภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.