Наконец-то мне удалось решить это самому: D Как сказано в комментарии, я должен «встроить его» в UIKit и использовать его в SwiftUI
Сначала:
struct AirPlayButton: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<AirPlayButton>) -> UIViewController {
return AirPLayViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<AirPlayButton>) {
}
}
Затем класс c ViewController, откуда мы знаем от веков как показать это знаменитое всплывающее меню AirPlay:
class AirPLayViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let isDarkMode = self.traitCollection.userInterfaceStyle == .dark
let button = UIButton()
let boldConfig = UIImage.SymbolConfiguration(scale: .large)
let boldSearch = UIImage(systemName: "airplayaudio", withConfiguration: boldConfig)
button.setImage(boldSearch, for: .normal)
button.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
button.backgroundColor = .red
button.tintColor = isDarkMode ? .white : .black
button.addTarget(self, action: #selector(self.showAirPlayMenu(_:)), for: .touchUpInside)
self.view.addSubview(button)
}
@objc func showAirPlayMenu(_ sender: UIButton){ // copied from https://stackoverflow.com/a/44909445/7974174
let rect = CGRect(x: 0, y: 0, width: 0, height: 0)
let airplayVolume = MPVolumeView(frame: rect)
airplayVolume.showsVolumeSlider = false
self.view.addSubview(airplayVolume)
for view: UIView in airplayVolume.subviews {
if let button = view as? UIButton {
button.sendActions(for: .touchUpInside)
break
}
}
airplayVolume.removeFromSuperview()
}
}
Наконец, в SwiftUI просто вызовите:
struct ContentView: View {
var body: some View {
VStack {
Text("Hello World")
AirPlayButton().frame(width: 40, height: 40) // (important to be consistent with this frame, like that it is nicely centered... see button.frame in AirPlayViewController)
}
}
}