2017-01-20 9 views
2

Я использую AvPlayer и пытаюсь настроить слайдер, чтобы разрешить чистку аудиофайлов. У меня проблема с ползунком, прыгающим по всему месту, когда его выбрали. Затем он возвращается к исходной позиции на секунду, прежде чем возвращаться к месту, куда он был перетащен.Jumpy UISlider при очистке - использование UISlider с AVPlayer

Вы не можете видеть мой курсор на Gif, но гладкие удлиненные перетаскивания - это перемещение ручки, а быстрые хлысты - слайдер.

enter image description here

Ive потратили часы и прибегая к помощи расчесывания через переполнение стека и не могу понять, что я делаю неправильно здесь, много подобных вопросов довольно стары и в ObjC.

Это раздел кода, который, как я думаю, несет ответственность за проблему, он обрабатывает событие перемещаемого ползунка: Ive пробовал его без инструкции 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) 
    } 
} 

Я расскажу о своем полном классе ниже для справки.

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 
    } 

} 

ответ

1

вам необходимо удалить наблюдатель и отменить таймеры, как только пользователь выбирает большой палец на слайдер и добавить их обратно при перетаскивании делается

делать добавить цели, как это, где загрузив плеер:

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 и вызывать их при необходимости

+0

Эй, Мохи, вы решили проблему? Я тоже столкнулся с этим. –

+0

Да @JamesRao, это было вызвано моими наблюдателями и таймерами (для отображения/скрытия панелей инструментов автоматически через несколько секунд), я удаляю их каждый раз, когда пользователь прикасается к изображению большого пальца слайдера и добавляет их обратно, когда пользователь отпускает слайдер :) –

+0

Я, наконец, сделал это, сделав паузу при прикосновении вниз и играя прикосновением. Спасибо огромное! :) –

0

Попробуйте использовать значение ползунка времени, как показано ниже:

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

и передать значение ползунка, когда пользователь отключился слайдер, также не обновлять значение слайдера тока играя во время взаимодействия пользователя на слайдере