web-dev-qa-db-ja.com

UISliderをタップして値を設定します

Slider(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()関数には入りません。

何が悪いのですか?または、私が達成しようとしていることを達成するためのより良い方法はありますか?

18
senty

上記のコード例に従って、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)      
    }
}

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

UISliderをサブクラス化し、常にtrueをbeginTrackingに返すだけで、望ましい効果が得られるようです。

iOS 10およびSwift

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

その後、コードでUISliderの代わりにCustomSliderを使用します。

31
pteofil

これは「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)
    }
}
1
Diogo Souza

私はこのアプローチが好きです

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

後で電話するだけ

let slider = UISlider()
slider.addTapGesture()
0
Adam

おそらく最も簡単な解決策は、「内部の修正」アクションを使用して、インターフェイスビルダーを介して接続することです。

@IBAction func finishedTouch(_ sender: UISlider) {

    finishedMovingSlider(sender)
}

これは、指が電話画面から離れるとすぐに呼び出されます。

0
znx

プテオフィルの答えはここで受け入れられる答えでなければなりません。

以下は、すべての人が興味を持つXamarinのソリューションです。

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

Pteofilが言及したように、これを機能させるにはUISliderをサブクラス化する必要があります。

0
PunainenAurinko