简体   繁体   中英

Fade (animate) Volume using MPMediaPlayer Swift 4

I'm using Xcode 10+, Swift 4, and targeting iOS 11.4+ with MPMediaPlayer

I'd like to programmatically fade out the volume of the player (like Apple does when you quit their music player). As well, I don't want to see anything (like the VolumeView display) when it functions.

It looks like all the programmatic volume controls have been deprecated.

I've read through a lot of related posts and created this function which has several problems:

@objc func fadeVolume(){
    var sliderView = UISlider()
    //let volumeView = MPVolumeView(frame: CGRect.init(x: self.view.frame.maxX, y: self.view.frame.maxY, width: 0, height: 0))
    let volumeView = MPVolumeView(frame: .zero)
    volumeView.clipsToBounds = true
    volumeView.showsRouteButton = false
    //volumeView.isHidden = true
    volumeView.alpha = 0.001
    for subview in volumeView.subviews {
        if let slider = subview as? UISlider {
            sliderView = slider
            break
        }
    }
    self.view.addSubview(volumeView)
    volumeView.didMoveToSuperview()

    let current:Float = AVAudioSession.sharedInstance().outputVolume
    print("slider value: \(current)")
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
        UIView.animate(withDuration: 0.4, animations: {
            sliderView.setValue(0.0, animated: false)
        }, completion: { finished in
            // If either one of these is uncommented, the VolumeView will display.
            // However, without removing from superview, the VolumeView stays hidden even when I use the phone volume buttons.
            volumeView.removeFromSuperview()
            //volumeView.alpha = 1.0
        })
    }
}

First problem: The VolumeView display shows onscreen. I've tried using different frames, and changing the alpha, etc. It's as though the animation never occurs and it goes directly to the completion block.

Second problem: The VolumeView really needs to be removed from the superview or else it will remain hidden even when I use the phone volume buttons. It should only be hidden during the execution of this function.

Third problem: The animate block does nothing. The volume will simply go from the starting point to 0 instantly - no fade.

Fourth problem: I haven't tested this but my assumption is that this won't work when the app is in the background. So the idea of using this to fade out the volume when quitting the app might not work.

Any idea how to fade out the volume without displaying anything onscreen? The answer does not necessarily need to use MPVolumeView, but I need it to work with MPMediaPlayer and when exiting the App.

EDIT: Below is my modified code which will fade the volume, however the issue of being able to do this when my app terminates still exists. I can call this code from 'appWillTerminate' however it does not run completely as the app terminates before it can loop through all the way.

// Public in ViewController Class:
let volumeView = MPVolumeView()
var sliderView = UISlider()
var currentVolume:Float = 0

//This called by a notification:
    @objc func fadeVolume(){
        // A lot of other posts use these to hide the volume view however I only needed the alpha change
        //volumeView.clipsToBounds = true
        //volumeView.showsRouteButton = false
        //volumeView.isHidden = true
        //print("volume alpha \(volumeView.alpha)")
        volumeView.alpha = 0.001
        self.view.addSubview(volumeView)
        volumeView.didMoveToSuperview()
        if let view = volumeView.subviews.first as? UISlider {
            sliderView = view
        }
        print("slider value: \(sliderView.value)")
        currentVolume = sliderView.value
        changeVolumeSlowly()
    }
    @objc func changeVolumeSlowly(){
        sliderView.value = sliderView.value - 0.1
        print("\(sliderView.value)")
        if sliderView.value > 0 {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
                self?.changeVolumeSlowly()
            }
        } else {
            myMP.pause()
            myMP.stop()
            //reset
            // Since the volumeView is 'global' to the app, if you do not change
            // it back to the previous volume and make it visible you won't see it unless you restart your app.
            //Unfortunately these cause the volume view to flash onscreen
            volumeView.alpha = 1.0
            sliderView.value = currentVolume
            volumeView.removeFromSuperview()
        }
    }

Make your UISlider variable public and use this function to fade the volume sound.

@objc func changeVolumeSlowly(){
    sliderView.value = sliderView.value - 0.1
    print("\(sliderView.value)")
    if sliderView.value > 0 {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
            self?.changeVolumeSlowly()
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM