我想在我的相机应用程序中实现音量快门.当用户按下音量按钮时,我应该得到一个事件来拍照.
我正在寻找满足以下要求的实现:
>即使音量当前处于最大值,它也应该工作,并且用户按下音量增大按钮.
>应该没有屏幕上的UI显示音量已更改.
>应该没有已知的Apple拒绝使用此技术的应用程序的案例.
关于这个主题存在其他问题和答案,但对于旧版本的iOS,我想找到一个适用于iOS 11的版本.
ProCamera,ProCam和Camera等相机应用程序具有满足所有这些条件的音量快门,因此显然可行.
最佳答案 所以这里的代码将满足您的所有要求.
我在StackOverflow上从问题/答案中提取了所有这些代码.
Apple将拒绝使用此代码提交的所有应用.
Tested with iOS 10.2 in Xcode 8.3.1
您需要使用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")
}
}
视图控制器
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")
}
}