擦洗时使用Jumpy UISlider – 在AVPlayer上使用UISlider
我正在使用AvPlayer,并试图设置滑块以允许清理audio文件。 我有一个问题,滑块跳过所有的地方,当它被选中。 然后在返回到被拖动的位置之前,它会返回原始位置一秒钟。
你不能在Gif上看到我的光标,但光滑的细长拖动是我移动旋钮,然后快速鞭子是滑块行为不端。
我花了数小时search,并通过堆栈溢出梳理,不能找出我在这里做错了什么,很多类似的问题是相当老,在ObjC。
这是代码段,我认为是负责的问题,它处理的滑块被移动事件:我试过了,没有if语句也没有看到不同的结果。
@IBAction func horizontalSliderActioned(_ sender: Any) { horizontalSlider.isContinuous = true if self.horizontalSlider.isTouchInside { audioPlayer?.pause() let seconds : Int64 = Int64(horizontalSlider.value) let preferredTimeScale : Int32 = 1 let seekTime : CMTime = CMTimeMake(seconds, preferredTimeScale) audioPlayerItem?.seek(to: seekTime) audioPlayer?.play() } else { let duration : CMTime = (self.audioPlayer?.currentItem!.asset.duration)! let seconds : Float64 = CMTimeGetSeconds(duration) self.horizontalSlider.value = Float(seconds) } }
我将在下面列出我的全class作为参考。
import UIKit import Parse import AVFoundation import AVKit class PlayerViewController: UIViewController, AVAudioPlayerDelegate { @IBOutlet var horizontalSlider: UISlider! var selectedAudio: String! var audioPlayer: AVPlayer? var audioPlayerItem: AVPlayerItem? var timer: Timer? func getAudio() { let query = PFQuery(className: "Part") query.whereKey("objectId", equalTo: selectedAudio) query.getFirstObjectInBackground { (object, error) in if error != nil || object == nil { print("The getFirstObject request failed.") } else { print("There is an object now get the Audio. ") let audioFileURL = (object?.object(forKey: "partAudio") as! PFFile).url self.audioPlayerItem = AVPlayerItem(url: NSURL(string: audioFileURL!) as! URL) self.audioPlayer = AVPlayer(playerItem: self.audioPlayerItem) let playerLayer = AVPlayerLayer(player: self.audioPlayer) playerLayer.frame = CGRect(x: 0, y: 0, width: 10, height: 10) self.view.layer.addSublayer(playerLayer) let duration : CMTime = (self.audioPlayer?.currentItem!.asset.duration)! let seconds : Float64 = CMTimeGetSeconds(duration) let maxTime : Float = Float(seconds) self.horizontalSlider.maximumValue = maxTime self.audioPlayer?.play() self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(PlayerViewController.audioSliderUpdate), userInfo: nil, repeats: true) } } } @IBOutlet var playerButton: UIButton! func playerButtonTapped() { if audioPlayer?.rate == 0 { audioPlayer?.play() self.playerButton.setImage(UIImage(named: "play"), for: UIControlState.normal) } else { audioPlayer?.pause() self.playerButton.setImage(UIImage(named: "pause"), for: UIControlState.normal) } } override func viewDidLoad() { super.viewDidLoad() horizontalSlider.minimumValue = 0 horizontalSlider.value = 0 self.playerButton.addTarget(self, action: #selector(PlayerViewController.playerButtonTapped), for: UIControlEvents.touchUpInside) getAudio() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(PlayerViewController.finishedPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.audioPlayerItem) } override func viewWillDisappear(_ animated: Bool) { super.viewWillAppear(animated) // remove the timer self.timer?.invalidate() // remove the observer when leaving page NotificationCenter.default.removeObserver(audioPlayer?.currentItem! as Any) } func finishedPlaying() { // need option to play next track self.playerButton.setImage(UIImage(named: "play"), for: UIControlState.normal) let seconds : Int64 = 0 let preferredTimeScale : Int32 = 1 let seekTime : CMTime = CMTimeMake(seconds, preferredTimeScale) audioPlayerItem!.seek(to: seekTime) } @IBAction func horizontalSliderActioned(_ sender: Any) { horizontalSlider.isContinuous = true if self.horizontalSlider.isTouchInside { audioPlayer?.pause() let seconds : Int64 = Int64(horizontalSlider.value) let preferredTimeScale : Int32 = 1 let seekTime : CMTime = CMTimeMake(seconds, preferredTimeScale) audioPlayerItem?.seek(to: seekTime) audioPlayer?.play() } else { let duration : CMTime = (self.audioPlayer?.currentItem!.asset.duration)! let seconds : Float64 = CMTimeGetSeconds(duration) self.horizontalSlider.value = Float(seconds) } } func audioSliderUpdate() { let currentTime : CMTime = (self.audioPlayerItem?.currentTime())! let seconds : Float64 = CMTimeGetSeconds(currentTime) let time : Float = Float(seconds) self.horizontalSlider.value = time } }
你需要删除观察员和无效的定时器,只要用户select滑块上的拇指,并在拖动完成后再次添加
在你加载你的播放器的地方添加这样的目标:
mySlider.addTarget(self, action: #selector(PlayerViewController.mySliderBeganTracking(_:)), forControlEvents:.TouchDown) mySlider.addTarget(self, action: #selector(PlayerViewController.mySliderEndedTracking(_:)), forControlEvents: .TouchUpInside) mySlider.addTarget(self, action: #selector(PlayerViewController.mySliderEndedTracking(_:)), forControlEvents: .TouchUpOutside )
并删除观察者和无效的定时器在mySliderBeganTracking
然后添加观察员在mySliderEndedTracking
更好地控制播放器中发生的事情写2个函数: addObservers
和removeObservers
并在需要时调用它们
尝试使用如下所示的时间滑块值:
@IBAction func timeSliderDidChange(_ sender: UISlider) { AVPlayerManager.sharedInstance.currentTime = Double(sender.value) } var currentTime: Double { get { return CMTimeGetSeconds(player.currentTime()) } set { if self.player.status == .readyToPlay { let newTime = CMTimeMakeWithSeconds(newValue, 1) player.seek(to: newTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero) { ( _ ) in self.updatePlayerInfo() } } } }
并在用户释放滑块时传递滑块的值,也不会在滑块上发生用户交互时更新当前播放的滑块值