我想在相机应用中实现音量快门。当用户按下音量按钮时,我应该得到一个事件来拍照。
我正在寻找满足以下要求的实施:
即使当前音量最大,它也应该起作用,并且用户按下增大音量按钮。
屏幕上的UI不应显示音量已更改。
苹果应该没有已知的情况拒绝使用该技术的应用程序。
关于此主题还存在其他问题和答案,但对于iOS的较早版本,因此我想找到一个适用于iOS 11的问题。
ProCamera,ProCam和Camera +之类的相机应用程序具有满足所有这些条件的音量快门,因此这显然是可能的。
因此,这是可以满足您所有要求的代码-不过,我不确定Apple是否会批准。
我已经从StackOverflow上的问题/答案中提取了所有这些代码。
在Xcode 8.3.1中使用iOS 10.2测试
您需要使用AVFoundation
和MediaPlayer
框架才能使其正常工作。
import UIKit import AVFoundation import MediaPlayer class ViewController: UIViewController { //keeps track of the initial volume the user had set when entering the app //used to reset the volume when he exits the app var volume: Float = 0 override func viewDidLoad() { super.viewDidLoad() let audioSession = AVAudioSession.sharedInstance() volume = audioSession.outputVolume-0.1 //if the user is at 1 (full volume) try! audioSession.setActive(true) audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil) //prevents the volume hud from showing up let volView = MPVolumeView(frame: .zero) view.addSubview(volView) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { //when the user changes the volume, //prevent the output volume from changing by setting it to the default volume we specified, //so that we can continue pressing the buttons for ever (MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(volume, animated: false) //implement your photo-capturing function here print("volume changed") } }
如果要确保用户退出应用程序后代码仍可正常工作,请在应用程序激活时使用AppDelegate安装观察程序,如下所示:
AppDelegate
import UIKit import AVFoundation import MediaPlayer var volume: Float = 0.5 @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? let audioSession = AVAudioSession.sharedInstance() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { return true } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { (MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(volume, animated: false) NotificationCenter.default.removeObserver(self) NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "volumeChanged"))) } func applicationDidBecomeActive(_ application: UIApplication) { volume = audioSession.outputVolume if volume == 0 { volume += 0.1 } else if volume == 1 { volume -= 0.1 } try! audioSession.setActive(true) audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil) } func applicationWillResignActive(_ application: UIApplication) { audioSession.removeObserver(self, forKeyPath: "outputVolume") } }
ViewController
import UIKit import AVFoundation import MediaPlayer class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(self.volumeChanged), name: Notification.Name(rawValue: "volumeChanged"), object: nil) //prevents the volume hud from showing up let volView = MPVolumeView(frame: .zero) view.addSubview(volView) } func volumeChanged() { print("volume changed") } }