観察するとrate
とstatus
がうまくいくはずです - 観測コールバックは私のコードで呼び出されるので、私もあなたのために働くと思います。私は問題は、ビデオが一時停止しているときにだけ呼び出され、ユーザーがそれをスクラブしたときではないということです。だから私はそれに答えます。
おそらく観察したいことはcurrentTime
となります。私は自分で試してみましたが、AVPlayer
またはそのcurrentItem
を観察しようとすると、KVOは呼び出されません。私は少しの研究をしましたが、これは単純に機能しません(this SO question参照)。あなたはそれを行う別の方法を見つける必要があります。 1つの方法は、タイマーを追加し、タイマーの状態を定期的にチェックすることです。 rate
またはtimeControlStatus
(see this answer)を見ると組み合わせると、ビデオが一時停止していても、currentTimeがユーザーによって変更されていることがわかります。
私はあなたがスウィフトコードを読んで気にしない、これは最初のアプローチになります願っています:
class ViewController: UIViewController {
let player = AVPlayerViewController()
var timer: Timer? = nil
var previousTime: Double = 0
var stopped = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
present(player, animated: true, completion: {
self.player.player = AVPlayer(url: URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")!)
self.player.player?.play()
self.player.player?.addObserver(self, forKeyPath: "rate", options: .new, context: nil)
self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { (timer) in
let currentTime = self.player.player?.currentTime().seconds ?? 0
if self.previousTime != currentTime && self.stopped {
print(">>> User scrubbing")
}
self.previousTime = currentTime
})
})
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "rate" && (change?[NSKeyValueChangeKey.newKey] as? Float) == 0 {
print(">>> stopped")
stopped = true
} else if keyPath == "rate" && (change?[NSKeyValueChangeKey.newKey] as? Float) == 1 {
print(">>> played again")
stopped = false
}
}
}
第二のアプローチ、私が好む1、AVPlayerをサブクラス化し、そのseek(to:toleranceBefore:toleranceAfter:completionHandler:)
メソッドをオーバーライドしています。このメソッドは、ユーザーがビデオをスクラブするときにAVPlayerViewController
によって呼び出されます。この時点で、ユーザーがスクラビングしていることがわかります(ビデオの再生中にユーザーがスクラブしたときにも呼び出されますが、演奏)。
class CustomAVPlayer: AVPlayer {
override func seek(to time: CMTime, toleranceBefore: CMTime, toleranceAfter: CMTime, completionHandler: @escaping (Bool) -> Void) {
super.seek(to: time, toleranceBefore: toleranceBefore, toleranceAfter: toleranceAfter, completionHandler: completionHandler)
// if you don't call this method directly, it's called only by the
// AVPlayerViewController's slider during scrubbing
print(">> user scrubbing")
}
}
私は本当に助けてくれた2番目のアプローチを使用しました。 –
ユーザーが2番目の方法でスクラビングを停止したときに表示されます。 –
私が恐れているのは、ユーザーがスライダに触れていることを検出したいのであって、彼女がそれを動かすのではなく、私が示唆したアプローチのいずれによっても可能ではないということです。どちらも現在の時間を変更することに頼っていますが、ユーザがスライダに触れながらスライダに触れてもスライダに触れないようにしている場合、ユーザがスライダを再び動かすまで、seekメソッドは再び呼び出されません。 –