Нажмите на UISlider для установки значения

Я создал слайдер (работающий как контроль над видео, как у YouTube внизу) и установите максимальные (длительность) и минимальные значения. А затем использовал SeekToTime, чтобы изменить currentTime. Теперь пользователь может скользить большим пальцем ползунка, чтобы изменить значение

То, что я хочу достичь, это позволить пользователю нажимать в любом месте ползунка и устанавливать текущее время видео.

У меня есть подход от этого ответа, и я попытался применить его к моему делу, но не смог заставить его работать

class ViewController: UIViewController, PlayerDelegate {

var slider: UISlider!

override func viewDidLoad() {
  super.viewDidLoad()

  // Setup the slider
}

func sliderTapped(gestureRecognizer: UIGestureRecognizer) {
  //  print("A")

  let pointTapped: CGPoint = gestureRecognizer.locationInView(self.view)

  let positionOfSlider: CGPoint = slider.frame.origin
  let widthOfSlider: CGFloat = slider.frame.size.width
  let newValue = ((pointTapped.x - positionOfSlider.x) * CGFloat(slider.maximumValue) / widthOfSlider)

  slider.setValue(Float(newValue), animated: true)      
 }
}

Я думал, что это должно сработать, но не повезло. Затем я попробовал отладку с попыткой распечатать "A" в журналах, но, похоже, он не входит в функцию sliderTapped().

Что я делаю неправильно? Или есть лучший способ достичь того, чего я пытаюсь достичь?

Ответ 1

Похоже, вам нужно фактически инициализировать распознаватель жестов в вашем представленииDidLoad() для примера кода выше. Там есть комментарий, но я не вижу, как распознаватель создается где угодно.

Swift 2:

class ViewController: UIViewController {

    var slider: UISlider!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Setup the slider

        // Add a gesture recognizer to the slider
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "sliderTapped:")
        self.slider.addGestureRecognizer(tapGestureRecognizer)
    }

    func sliderTapped(gestureRecognizer: UIGestureRecognizer) {
        //  print("A")

        let pointTapped: CGPoint = gestureRecognizer.locationInView(self.view)

        let positionOfSlider: CGPoint = slider.frame.origin
        let widthOfSlider: CGFloat = slider.frame.size.width
        let newValue = ((pointTapped.x - positionOfSlider.x) * CGFloat(slider.maximumValue) / widthOfSlider)

        slider.setValue(Float(newValue), animated: true)      
    }
}

Swift 3:

class ViewController: UIViewController {

    var slider: UISlider!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Setup the slider

        // Add a gesture recognizer to the slider
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(sliderTapped(gestureRecognizer:)))
        self.slider.addGestureRecognizer(tapGestureRecognizer)
    }

    func sliderTapped(gestureRecognizer: UIGestureRecognizer) {
        //  print("A")

        let pointTapped: CGPoint = gestureRecognizer.location(in: self.view)

        let positionOfSlider: CGPoint = slider.frame.origin
        let widthOfSlider: CGFloat = slider.frame.size.width
        let newValue = ((pointTapped.x - positionOfSlider.x) * CGFloat(slider.maximumValue) / widthOfSlider)

        slider.setValue(Float(newValue), animated: true)
    }
}

Ответ 2

Похоже, что просто подклассифицировать UISlider и всегда возвращать true для beginTracking, вы получите желаемый эффект.

iOS 10 и Swift 3

class CustomSlider: UISlider {
    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        return true
    }
}

Используйте CustomSlider вместо UISlider после этого в вашем коде.

Ответ 3

Это мой код, основанный на ответе "myuiviews".
Я исправил 2 маленьких "ошибки" исходного кода.

1 - Нажатие на 0 было слишком сложным, поэтому я упростил его  2 - Сдвиг большого пальца слайдера немного активировал "tapGestureRecognizer", который заставляет его вернуться в исходное положение, поэтому я добавил фильтр минимального расстояния, чтобы этого избежать.

Swift 4

class ViewController: UIViewController {

    var slider: UISlider!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Setup the slider

        // Add a gesture recognizer to the slider
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(sliderTapped(gestureRecognizer:)))
        self.slider.addGestureRecognizer(tapGestureRecognizer)
    }

    @objc func sliderTapped(gestureRecognizer: UIGestureRecognizer) {
        //  print("A")

        var pointTapped: CGPoint = gestureRecognizer.location(in: self.view)
        pointTapped.x -= 30  //Subtract left constraint (distance of the slider origin from "self.view" 

        let positionOfSlider: CGPoint = slider.frame.origin
        let widthOfSlider: CGFloat = slider.frame.size.width

        //If tap is too near from the slider thumb, cancel
        let thumbPosition = CGFloat((slider.value / slider.maximumValue)) * widthOfSlider
        let dif = abs(pointTapped.x - thumbPosition)
        let minDistance: CGFloat = 51.0  //You can calibrate this value, but I think this is the maximum distance that tap is recognized
        if dif < minDistance { 
            print("tap too near")
            return
        }

        var newValue: CGFloat
        if pointTapped.x < 10 {
            newValue = 0  //Easier to set slider to 0
        } else {
            newValue = ((pointTapped.x - positionOfSlider.x) * CGFloat(slider.maximumValue) / widthOfSlider)
        }



        slider.setValue(Float(newValue), animated: true)
    }
}

Ответ 4

Ответ pteofil должен быть принятым ответом здесь.

Ниже приведено решение для Xamarin для всех желающих:

public override bool BeginTracking(UITouch uitouch, UIEvent uievent)
{
    return true;
}

Как указано в pteofil, вам нужно подклассифицировать UISlider, чтобы это работало.