【问题标题】:How do I implement a volume shutter in iOS 11?如何在 iOS 11 中实现音量快门?
【发布时间】:2017-01-12 16:16:25
【问题描述】:

我想在我的相机应用中实现音量快门。当用户按下音量按钮时,我应该得到一个拍照的事件。

我正在寻找满足以下要求的实现:

  • 即使当前音量处于最大,并且用户按下音量调高按钮,它也应该可以工作。
  • 屏幕上的 UI 不应显示音量已更改。
  • 应该没有已知的 Apple 拒绝使用此技术的应用程序的案例。

关于这个主题还有其他问题和答案,但对于旧版本的 iOS,所以我想找到一个适用于 iOS 11 的问题和答案。

像 ProCamera、ProCam 和 Camera+ 这样的相机应用具有满足所有这些条件的音量快门,因此这显然是可能的。

【问题讨论】:

  • 到目前为止你尝试过什么?给我们看一些代码。
  • @backslash-f 我不确定要尝试什么技术,因为我研究的所有技术都存在上述缺陷。在进行大量试验和错误之前,我想看看是否已经找到了更好的解决方案。
  • @ColdSteel 其他堆栈溢出答案指出,五年前有效的许多音量快门技术不再适用于现代 iOS 版本。
  • 没有人能保证你的第三个条件! :)

标签: ios iphone ios11 avcapture shutter


【解决方案1】:

所以这里的代码可以满足你的所有要求——不过我不确定 Apple 是否会批准它。
我已经从 StackOverflow 上的问题/答案中提取了所有这些代码。

在 Xcode 8.3.1 中使用 iOS 10.2 测试

您需要使用AVFoundationMediaPlayer 框架才能使其工作。

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

【讨论】:

  • 谢谢。当我切换到另一个应用程序并返回时,它不再起作用 - 调整铃声音量。
  • 请记住,这不是一个服务网站。你不能指望人们不亲自尝试就给出完整的解决方案。我提供的代码是您问题的一个不错的基本解决方案,您应该开始调整它以完全满足您的要求。
  • 我想检查是否有人已经找到了一个答案,可以在花时间再次弄清楚之前找到所有边缘情况,顺便说一句,我经常这样做。如果您只有部分解决方案,那很好,我很感激您给我的东西。我的评论也将对其他人看到您的答案有用。如果在到期时没有更好的答案,我会奖励你。
  • 因此,经过大约 5 分钟的额外编码,我找到了您在评论中提到的问题的解决方案。请参阅我的更新答案。
  • 您可能想要处理当用户点击音量按钮时检测到两次按下的问题,因此为此实施某种计数器。
【解决方案2】:

根据 Apple 的 App Store Review Guidelines,这将是拒绝的明确理由。

2.5.9 改变标准开关功能(例如音量增大/减小和响铃/静音开关)或其他原生用户界面元素或行为的应用程序将被拒绝。

来源:Is it possible to disable volume buttons in iOS apps?

【讨论】:

  • 但是 snapchat 是怎么做到的呢?有什么想法吗?
  • 感谢相关的主要来源。也许它被认为是一个合法的、可预期的功能,就像 Apples Camera App 一样,因此在用于拍照时不会“改变”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 1970-01-01
  • 2018-10-23
  • 2013-01-06
  • 1970-01-01
  • 2015-06-17
相关资源
最近更新 更多