点击UISlider设置值

时间:2016-01-05 19:14:57

标签: ios swift uigesturerecognizer uislider uitapgesturerecognizer

我创建了一个Slider(作为视频的控件,就像YouTube在底部一样)并设置最大值(持续时间)和最小值。然后使用SeekToTime更改currentTime。现在,用户可以滑动滑块的拇指以更改值

我想要实现的是让用户点按滑块上的任意位置并设置视频的当前时间。

我从this answer得到了一个方法,我尝试将其应用到我的案例中,但无法使其正常工作

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()功能。

我做错了什么?或者有更好的方法来实现我想要实现的目标吗?

7 个答案:

答案 0 :(得分:27)

根据上面的代码示例,您需要在viewDidLoad()中实际初始化点击手势识别器。那里有评论,但我没有看到识别器在任何地方被创建。

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

斯威夫特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)
    }
}

答案 1 :(得分:27)

它似乎只是对UISlider进行子类化并且返回始终为true的beginTracking会产生所需的效果。

iOS 10和Swift 3

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

然后在代码中使用CustomSlider而不是UISlider。

答案 2 :(得分:1)

这是我的代码,基于" 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's 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)
    }
}

答案 3 :(得分:1)

但是,我实施了 pteofil,因为我已经将一个操作附加到 valueChanged,我在跟踪方面遇到了问题。

我正在查看 Adam 的回答,我注意到他也做了一个非常好的实现,只是我通常不喜欢添加手势识别器。所以我结合了两个答案(有点),现在我可以使用滑动来改变值(从而触发 valueChanged 以及如果点击滑块:

  1. 我继承了 UISlider,并覆盖了 beginTracking 方法:
    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        return true //Without this, we don't get any response in the method below 
    }
  1. 然后我覆盖了 touchEnded 方法(我猜你也可以覆盖其他状态,但这似乎是逻辑上最适合的一个)
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let location = touch.location(in: self)
        let conversion = minimumValue + Float(location.x / bounds.width) * maximumValue
        setValue(conversion, animated: false)
        sendActions(for: .valueChanged) //Add this because without this it won't work.
    }

我在其他地方也有我的标准 IBAction(这与上面没有直接关系,但我添加它是为了提供完整的上下文):

    @IBAction func didSkipToTime(_ sender: UISlider) {
        print("sender value: \(sender.value)") // Do whatever in this method
    }

希望它会有所帮助并满足您的需求。

答案 4 :(得分:0)

pteofil的答案应该是这里接受的答案。

以下是每个人都感兴趣的Xamarin解决方案:

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

正如pteofil所提到的,你需要为UISlider创建子类以使其正常工作。

答案 5 :(得分:0)

最简单的解决方案是使用“内部修饰”操作,通过界面构建​​器连接。

@IBAction func finishedTouch(_ sender: UISlider) {

    finishedMovingSlider(sender)
}

一旦手指离开手机屏幕,就会立即调用。

答案 6 :(得分:0)

我喜欢这种方法

backgroundColor

然后打电话给

extension UISlider {
    public func addTapGesture() {
        let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        addGestureRecognizer(tap)
    }

    @objc private func handleTap(_ sender: UITapGestureRecognizer) {
        let location = sender.location(in: self)
        let percent = minimumValue + Float(location.x / bounds.width) * maximumValue
        setValue(percent, animated: true)
        sendActions(for: .valueChanged)
    }
}