Пан Жест с AVPlayer
Эта функция очень важна для моего приложения, и ей действительно нужна помощь. В основном, я хочу добавить UIPanGestureRecognizer
на видеоплеер, чтобы пользователь мог перемотать видео вперед или назад с помощью жеста.
У Apple есть некоторый пример кода, который использует Swift 3 и уже создан весь видеоплеер. Не хватает только UIPanGestureRecognizer
, Это ссылка: https://developer.apple.com/library/content/samplecode/AVFoundationSimplePlayer-iOS/Introduction/Intro.html
В viewWillAppear
Я добавил жест так:
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture))
view.addGestureRecognizer(panGesture)
Это код, который работает несколько. Это в настоящее время чистит.
Проблема в том, что каждый раз, когда я запускаю жест панорамирования, видео переходит к середине, и я начинаю оттуда. Вместо быстрой перемотки вперед / назад от того места, где в данный момент находится видео, жест панорамирования пропускает видео до середины, а затем позволяет перематывать вперед / назад, что не очень хорошо.
func handlePanGesture(sender: UIPanGestureRecognizer) {
switch sender.state {
case .began, .changed:
let translation = sender.translation(in: self.view)
var horizontalTranslation = Float(translation.x)
let durationInSeconds = Float(CMTimeGetSeconds(player.currentItem!.asset.duration))
// Using 275 as the limit for delta along x
let translationLimit: Float = 275
let minTranslation: Float = -1 * translationLimit
let maxTranslation: Float = translationLimit
if horizontalTranslation > maxTranslation {
horizontalTranslation = maxTranslation
}
if horizontalTranslation < minTranslation {
horizontalTranslation = minTranslation
}
let timeToSeekTo = normalize(delta: horizontalTranslation , minDelta: minTranslation, maxDelta: maxTranslation, minDuration: 0, maxDuration: durationInSeconds)
print("horizontal translation \(horizontalTranslation) \n timeToSeekTo: \(timeToSeekTo)")
let cmTime = CMTimeMakeWithSeconds(Float64(timeToSeekTo), self.player.currentTime().timescale)
player.seek(to: cmTime)
default:
print("default")
}
}
func normalize(delta: Float, minDelta: Float, maxDelta: Float, minDuration: Float, maxDuration: Float) -> Float {
let result = ((delta - minDelta) * (maxDuration - minDuration) / (maxDelta - minDelta) + minDuration)
return result
}
Любая помощь будет отличной - спасибо!
2 ответа
Спасибо за ваш код. Я использовал его, изменил несколько строк, он работает хорошо.
@objc func handlePanGesture(sender: UIPanGestureRecognizer) {
switch sender.state {
case .began, .changed:
let translation = sender.translation(in: self.view)
let horizontalTranslation = Float(translation.x)
let durationInSeconds = Float(CMTimeGetSeconds(player.currentItem!.asset.duration))
// normalize based on duration and width of the view
let scale:Float = durationInSeconds / Float(self.view.frame.width) / 4
// then you need to add the current time of player to avoid it starting from the middle.
let seekTime = horizontalTranslation * scale + Float((self.player.currentItem?.currentTime().seconds)!)
let cmTime = CMTimeMakeWithSeconds(Float64(Float(seekTime)), preferredTimescale: self.player.currentTime().timescale)
player.seek(to: cmTime)
print("horizontal translation \(horizontalTranslation) \n timeToSeekTo: \(seekTime)")
default:
print("default")
}
}
Я реализовал UIPanGesture
с AVPlayer
ниже мой рабочий код [swift 3]
,
func handleDraging(_ gesture:UIPanGestureRecognizer){
let location = gesture.location(in: self.playerView)
if gesture.state == .began {
print("\n\n-->---> Panning.state = .began at Point.x = \(location.x)")
self.playerLayer.player?.rate = 0
self.stopTimer()
}else if gesture.state == .changed {
let valocity = gesture.velocity(in: self.playerView)
print("\n\n-->---> Panning.state = .changed at Point.x = \(location.x)")
let percentage = Double(location.x) / Double(self.playerView.frame.width)
let currentTime = self.playerLayer.player!.currentTime()
let currentSeconds = CMTimeGetSeconds(currentTime)
var newSeconds = currentSeconds + percentage
if valocity.x < 0 {
newSeconds = currentSeconds - percentage
}
let newTime = CMTime(seconds: newSeconds, preferredTimescale: self.playerLayer.player!.currentTime().timescale)
self.playerLayer.player?.seek(to: newTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
let total = CGFloat(CMTimeGetSeconds(self.playerLayer.player!.currentItem!.asset.duration))
let seconds = CGFloat(CMTimeGetSeconds(newTime))
self.interval = Double(seconds)//here update your CurrentTimelabel.text .....
let temp = seconds/total
self.progress = Float(temp)//here update your UIProgressBar.progress .....
print("\n\t-->Total Progress = \(temp)")
}else if gesture.state == .ended || gesture.state == .failed || gesture.state == .recognized {
gesture.setTranslation(CGPoint.zero, in: self.playerView)
self.startTimer()
self.playerLayer.player?.playImmediately(atRate: 1)
}
}