iOS 9:如何在不显示系统条形音箱弹出窗口的情况下以编程方式更改音量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33168497/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:01:34  来源:igfitidea点击:

iOS 9: How to change volume programmatically without showing system sound bar popup?

iosobjective-cios9mpmusicplayercontrollermpvolumeview

提问by mgv

I have to change the volume on iPad and using this code:

我必须更改 iPad 上的音量并使用以下代码:

[[MPMusicPlayerController applicationMusicPlayer] setVolume:0];

But this changing volume and showing system volume bar on iPad. How to change the sound without showing the volume bar?

但是这个不断变化的音量并在 iPad 上显示系统音量条。如何在不显示音量条的情况下更改声音?

I know, setVolume:is deprecated, and everybody says to use MPVolumeView. If this is the only way to solve my problem, then how to change the volume using MPVolumeView? I don't see any method in MPVolumeViewthat changes the sound.
Should I use some another class together with MPVolumeView?

我知道,setVolume:已弃用,每个人都说要使用MPVolumeView. 如果这是解决我的问题的唯一方法,那么如何使用MPVolumeView? 我没有看到任何MPVolumeView改变声音的方法。
我应该与其他类一起使用MPVolumeView吗?

But it's preferable to use MPMusicPlayerController.

但最好使用MPMusicPlayerController.

Thank you for advice!

谢谢你的建议!

采纳答案by udjat

MPVolumeViewhas a slider, and by changing the value of the slider, you can change the device volume. I wrote an MPVolumeViewextension to easily access the slider:

MPVolumeView有一个滑块,通过改变滑块的值,可以改变设备音量。我写了一个MPVolumeView扩展来轻松访问滑块:

extension MPVolumeView {
    var volumeSlider:UISlider {
        self.showsRouteButton = false
        self.showsVolumeSlider = false
        self.hidden = true
        var slider = UISlider()
        for subview in self.subviews {
            if subview.isKindOfClass(UISlider){
                slider = subview as! UISlider
                slider.continuous = false
                (subview as! UISlider).value = AVAudioSession.sharedInstance().outputVolume
                return slider
            }
        }
        return slider
    }
}

回答by trungduc

For 2018, working on iOS 11.4

2018 年,在 iOS 11.4 上工作

You need to change slider.valueafter a small delay.

你需要slider.value在一个小的延迟后改变。

extension MPVolumeView {
  static func setVolume(_ volume: Float) {
    let volumeView = MPVolumeView()
    let slider = volumeView.subviews.first(where: { 
MPVolumeView.setVolume(0.5)
is UISlider }) as? UISlider DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) { slider?.value = volume } } }

Usage:

用法:

extension UIViewController {
  func setVolumeStealthily(_ volume: Float) {
    guard let view = viewIfLoaded else {
      assertionFailure("The view must be loaded to set the volume with no UI")
      return
    }

    let volumeView = MPVolumeView(frame: .zero)

    guard let slider = volumeView.subviews.first(where: { 
// set volume to 50%
viewController.setVolume(0.5)
is UISlider }) as? UISlider else { assertionFailure("Unable to find the slider") return } volumeView.clipsToBounds = true view.addSubview(volumeView) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { [weak slider, weak volumeView] in slider?.setValue(volume, animated: false) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { [weak volumeView] in volumeView?.removeFromSuperview() } } } }

Objective-C version

Objective-C 版本

回答by Senseful

MPVolumeView* volumeView = [[MPVolumeView alloc] init];

// Get the Volume Slider
UISlider* volumeViewSlider = nil;

for (UIView *view in [volumeView subviews]){
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        volumeViewSlider = (UISlider*)view;
        break;
    }
}

// Fake the volume setting
[volumeViewSlider setValue:1.0f animated:YES];
[volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];

Usage:

用法:

private let volumeView: MPVolumeView = MPVolumeView()
private var volumeSlider: UISlider?

回答by Abhinav

I don't think there is any way to change the volume without flashing volume control. You should use MPVolumeViewlike this:

我不认为有任何方法可以在不闪烁音量控制的情况下更改音量。你应该这样使用MPVolumeView

@IBOutlet weak var hiddenView: UIView!

回答by deebugger

Here's a solution in Swift. It might be a shady one, so I'll let you know if Apple approved this when I publish. Meantime, this works just fine for me:

这是 Swift 中的解决方案。这可能是一个阴暗的,所以我会在我发布时告诉你 Apple 是否批准了这个。同时,这对我来说很好用:

  1. Define an MPVolumeView and an optional UISlider in your View Controller

    override func viewDidLoad() {
        super.viewDidLoad()
    
        ...
    
        hiddenView.addSubview(volumeView)
        for view in volumeView.subviews {
            if let vs = view as? UISlider {
                volumeSlider = vs
                break
            }
        }
    }
    
  2. In the storyboard, define a view that's hidden from the user (height=0 should do the trick), and set an outlet for it (we'll call it hiddenViewhere). This step is only good if you want NOT to display the volume HUD when changing the volume (see note below):

    func someFunc() {
        if volumeSlider?.value < 0.99 {
            volumeSlider?.value += 0.01
        } else {
            volumeSlider?.value = 1.0
        }
    }
    
  3. In viewDidLoad() or somewhere init-y that runs once, catch the UISlider that actually controls the volume into the optional UISlider from step (1):

    private let volumeView: MPVolumeView = MPVolumeView()
    private var volumeSlider: UISlider?
    
  4. When you want to set the volume in your code, just set volumeSlider?.value to be anywhere between 0.0 and 1.0, e.g. for increasing the volume:

    @IBOutlet weak var hiddenView: UIView!
    
  1. 在你的视图控制器中定义一个 MPVolumeView 和一个可选的 UISlider

    override func viewDidLoad() {
        super.viewDidLoad()
    
        ...
    
        hiddenView.addSubview(volumeView)
        for view in volumeView.subviews {
            if let vs = view as? UISlider {
                volumeSlider = vs
                break
            }
        }
    }
    
  2. 在故事板中,定义一个对用户隐藏的视图(height=0 应该可以解决问题),并为其设置一个出口(我们将在此处将其称为 hiddenView)。此步骤仅适用于在更改音量时不显示音量 HUD 的情况(请参阅下面的注释):

    func someFunc() {
        if volumeSlider?.value < 0.99 {
            volumeSlider?.value += 0.01
        } else {
            volumeSlider?.value = 1.0
        }
    }
    
  3. 在 viewDidLoad() 或某个运行一次的 init-y 中,将实际控制音量的 UISlider 捕获到步骤 (1) 中的可选 UISlider 中:

    extension MPVolumeView {
        var volumeSlider: UISlider? {
            showsRouteButton = false
            showsVolumeSlider = false
            isHidden = true
            for subview in subviews where subview is UISlider {
                let slider =  subview as! UISlider
                slider.isContinuous = false
                slider.value = AVAudioSession.sharedInstance().outputVolume
                return slider
            }
            return nil
        }
    }
    
  4. 当您想在代码中设置音量时,只需将 volumeSlider?.value 设置为 0.0 和 1.0 之间的任意值,例如增加音量:

    extension MPVolumeView {
        var volumeSlider:UISlider { // hacking for changing volume by programing
            var slider = UISlider()
            for subview in self.subviews {
                if subview is UISlider {
                    slider = subview as! UISlider
                    slider.isContinuous = false
                    (subview as! UISlider).value = AVAudioSession.sharedInstance().outputVolume
                    return slider
                }
            }
            return slider
        }
    }
    

Important note:This solution will prevent the iPhone's Volume HUD from appearing- either when you change the volume in your code, or when the user clicks the external volume buttons. If you do want to display the HUD, then skip all the hidden view stuff, and don't add the MPVolumeView as a subview at all. This will cause iOS to display the HUD when the volume changes.

重要说明:此解决方案将阻止 iPhone 的音量 HUD 出现- 无论是在您更改代码中的音量时,还是在用户单击外部音量按钮时。如果您确实想显示 HUD,则跳过所有隐藏的视图内容,并且根本不要将 MPVolumeView 添加为子视图。这将导致 iOS 在音量改变时显示 HUD。

回答by BumMo Koo

@udjat 's answer in Swift 3

@udjat 在Swift 3 中的回答

let volumeView = MPVolumeView()

override func viewDidLoad() {
    ...
    view.addSubview(volumeView)
    volumeView.alpha = 0.00001
}

func changeSpeakerSliderPanelControls(volume: Float) {
    for subview in self.volumeView.subviews {

        if subview.description.rangeOfString("MPVolumeSlider") != nil {
             let slider = subview as! UISlider
             slider.value = volume

             break
        }
    }
}

回答by Jerome

Version: Swift 3 & Xcode 8.1

版本:Swift 3 & Xcode 8.1

import UIKit
import MediaPlayer

class UIVolumeSlider: UISlider {

    func activate(){
        updatePositionForSystemVolume()

        guard let view = superview else { return }
        let volumeView = MPVolumeView(frame: .zero)
        volumeView.alpha = 0.000001
        view.addSubview(volumeView)

        try? AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
        AVAudioSession.sharedInstance().addObserver(self, forKeyPath: "outputVolume", options: .new, context: nil)

        addTarget(self, action: #selector(valueChanged), for: .valueChanged)
    }


    func deactivate(){
        AVAudioSession.sharedInstance().removeObserver(self, forKeyPath: "outputVolume")
        removeTarget(self, action: nil, for: .valueChanged)
        superview?.subviews.first(where: {
@IBOutlet private var volumeSlider:UIVolumeSlider!
is MPVolumeView})?.removeFromSuperview() } func updatePositionForSystemVolume(){ try? AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation) value = AVAudioSession.sharedInstance().outputVolume } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "outputVolume", let newVal = change?[.newKey] as? Float { setValue(newVal, animated: true) } } @objc private func valueChanged(){ guard let superview = superview else {return} guard let volumeView = superview.subviews.first(where: {
volumeSlider.updatePositionForSystemVolume()
is MPVolumeView}) as? MPVolumeView else { return } guard let slider = volumeView.subviews.first(where: {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        volumeSlider.activate()
    }

    override func viewWillDisappear(_ animated: Bool) {
        volumeSlider.deactivate()
        super.viewWillDisappear(animated)
    }

is UISlider }) as? UISlider else { return } DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) { slider.value = self.value } } }

回答by CodeOverRide

Swift > 2.2, iOS > 8.0,

Swift > 2.2,iOS > 8.0,

I didn't find any solution I was looking but I end up doing this as solution:

我没有找到我正在寻找的任何解决方案,但我最终将其作为解决方案:

    import MediaPlayer

    class CusomViewCOntroller: UIViewController

    // could be IBOutlet
    var customSlider = UISlider()

    // in code
    var systemSlider =  UISlider()

    override func viewDidLoad() {
            super.viewDidLoad()

       let volumeView = MPVolumeView()
       if let view = volumeView.subviews.first as? UISlider{
          systemSlider = view
       }
    }

回答by dr OX

Here is my volume control for my audio player app:

这是我的音频播放器应用程序的音量控制:

systemSlider.value = customSlide.value

How to connect:

如何连接:

  1. Set UIVolumeSlider class in Identity Inspector on storyboard:
  1. 在情节提要的 Identity Inspector 中设置 UIVolumeSlider 类:

enter image description here

在此处输入图片说明

  1. Connect instance to class:
  1. 将实例连接到类:
##代码##
  1. In viewDidLoadmethod:
  1. viewDidLoad方法中:
##代码##
  1. Activate and deactivate it shitin didAppearand willDisappear:
  1. 激活和停用它拉屎didAppearwillDisappear
##代码##

回答by Андр?й Вахн?й

You can use default UISlider with this code:

您可以使用带有以下代码的默认 UISlider:

##代码##

next in code just write

接下来在代码中写

##代码##