滑动时出现跳动的UISlider-将UISlider与AVPlayer一起使用 [英] Jumpy UISlider when scrubbing - Using UISlider with AVPlayer

查看:53
本文介绍了滑动时出现跳动的UISlider-将UISlider与AVPlayer一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用AvPlayer,并试图设置一个滑块以允许清理音频文件.我在选择滑块时在滑块上到处跳跃时遇到问题.然后,它会回到原点位置一秒钟,然后再返回到被拖动到的位置.

I am using AvPlayer and am trying to set up a slider to allow scrubbing of audio files. Im having a problem with the slider jumping all over the place when its selected. It then goes back to the origin position for a second before going back to the location it was dragged to.

您看不到我的光标在Gif上,但是平滑的细长拖动使我移动了旋钮,然后快速的抽动就是滑块的行为异常.

You cant see my cursor on the Gif, but the smooth elongated drags are me moving the knob, then the quick whips are the slider misbehaving.

我花了数小时在整个堆栈溢出中进行谷歌搜索和梳理,却无法弄清我在做什么错,很多类似的问题已经很久了,并且存在于ObjC中.

Ive spent hours googling and combing through Stack Overflow and cant figure out what I'm doing wrong here, a lot of similar questions are quite old and in ObjC.

我认为这是导致问题的代码部分,它确实处理了滑块被移动的事件:我也尝试了没有if语句的滑块,并且没有看到不同的结果.

This is the section of code i think is responsible for the problem, it does handle the event of the slider being moved: Ive tried it without the if statement also and didn't see a different result.

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

我将在下面列出我的整个班级以供参考.

I will include my entire class below for reference.

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
    }

}

推荐答案

您需要在用户选择滑块上的拇指后立即删除观察者并使计时器无效,并在拖动完成后再次将其重新添加

you need to remove observers and invalidate timers as soon as user selects the thumb on slider and add them back again when dragging is done

在加载播放器的位置添加这样的目标:

to do add targets like this where you load your player:

    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个函数:addObserversremoveObservers并在需要时调用它们

and remove observers and invalidate timers in mySliderBeganTracking then add observers in mySliderEndedTracking for better control on what happens in your player write 2 functions : addObservers and removeObservers and call them when needed

这篇关于滑动时出现跳动的UISlider-将UISlider与AVPlayer一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆