SwiftUI方法
我花了一整天的时间来完成这个任务,因为我是新手,但我想出了一个解决方案:
A:可以读取音量
B:即使音量最大或最小也能正常工作
C:可能可以根据您的喜好进行自定义
struct VolumeEventReader<Content: View>: UIViewControllerRepresentable {
let builder: (Float) -> Content
class Coordinator: NSObject {
var parent: VolumeEventReader
var lastVolumeNotificationSequenceNumber: Int?
var currentVolume = AVAudioSession.sharedInstance().outputVolume
init(_ parent: VolumeEventReader) {
self.parent = parent
}
@objc func volumeChanged(_ notification: NSNotification) {
DispatchQueue.main.async { [self] in
volumeControlIOS15(notification)
}
}
func manageVolume(volume: Float, minVolume: Float) {
switch volume {
case minVolume: do {
currentVolume = minVolume + 0.0625
}
case 1: do {
currentVolume = 0.9375
}
default: break
}
if volume > currentVolume {
}
if volume < currentVolume {
}
parent.updateUIView(volume: volume)
currentVolume = volume
}
func volumeControlIOS15(_ notification: NSNotification) {
let minVolume: Float = 0.0625
if let volume = notification.userInfo!["Volume"] as? Float {
if let seqN = self.lastVolumeNotificationSequenceNumber {
if seqN == notification.userInfo!["SequenceNumber"] as! Int {
}
else {
self.lastVolumeNotificationSequenceNumber = (notification.userInfo!["SequenceNumber"] as! Int)
manageVolume(volume: volume, minVolume: minVolume)
}
}
else {
self.lastVolumeNotificationSequenceNumber = (notification.userInfo!["SequenceNumber"] as! Int)
manageVolume(volume: volume, minVolume: minVolume)
}
}
}
}
let viewController = UIViewController()
func makeUIViewController(context: Context) -> UIViewController {
let volumeView = MPVolumeView(frame: CGRect.zero)
volumeView.isHidden = true
viewController.view.addSubview(volumeView)
let childView = UIHostingController(rootView: builder(AVAudioSession.sharedInstance().outputVolume))
addChildViewController(childView, to: viewController)
return viewController
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
private func addChildViewController(_ child: UIViewController, to parent: UIViewController) {
if parent.children.count > 0{
let viewControllers:[UIViewController] = parent.children
for viewContoller in viewControllers{
viewContoller.willMove(toParent: nil)
viewContoller.view.removeFromSuperview()
viewContoller.removeFromParent()
}
}
parent.addChild(child)
child.view.translatesAutoresizingMaskIntoConstraints = false
parent.view.addSubview(child.view)
child.didMove(toParent: parent)
child.view.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
NSLayoutConstraint.activate([
child.view.leadingAnchor.constraint(equalTo: parent.view.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: parent.view.trailingAnchor),
child.view.topAnchor.constraint(equalTo: parent.view.topAnchor),
child.view.bottomAnchor.constraint(equalTo: parent.view.bottomAnchor)
])
}
func makeCoordinator() -> Coordinator {
let coordinator = Coordinator(self)
NotificationCenter.default.addObserver(
coordinator,
selector: #selector(Coordinator.volumeChanged(_:)),
name: NSNotification.Name(rawValue: "SystemVolumeDidChange"),
object: nil
)
return coordinator
}
func updateUIView(volume: Float) {
let childView = UIHostingController(rootView: builder(volume))
addChildViewController(childView, to: self.viewController)
}
}
这将为您提供一个VolumeEventReader,可以在Swift中使用,如下所示:
struct ContentView: View {
var body: some View {
VStack {
VolumeEventReader { volume in
VStack {
Text("Volume: \(volume)")
}
.onAppear {
print("\(volume)")
}
}
Text("Hello World")
}
}
}
注意:您可以将任何视图放置在VolumeEventReader中,我只是用VStack举了一个例子。这受到GeometryReader的启发。
感谢那些帮助我找到这个解决方案的答案:
iOS 15上的系统音量更改观察器无法工作
在SwiftUI中观察系统音量