'How to display the AirPlay Menu SwiftUI
Thanks to the airplay audio systemName emoji I made a nice icon
Button(action: {
showAirplay()
}, label: {
Image(systemName: "airplayaudio")
.imageScale(.large)
})
func showAirplay() {
???
}
But I have no idea how to display the famous menu :

Solution 1:[1]
Wrapping the AirPlay UIView for SwiftUI seems to be the best and simplest solution.
struct AirPlayView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let routePickerView = AVRoutePickerView()
routePickerView.backgroundColor = UIColor.clear
routePickerView.activeTintColor = UIColor.red
routePickerView.tintColor = UIColor.white
return routePickerView
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
Usage :
VStack {
AirPlayView()
}
Solution 2:[2]
func showAirplay() {
let rect = CGRect(x: 0, y: 0, width: 0, height: 0)
let airplayVolume = MPVolumeView(frame: rect)
airplayVolume.showsVolumeSlider = false
UIApplication.shared.windows.first?.addSubview(airplayVolume)
for view: UIView in airplayVolume.subviews {
if let button = view as? UIButton {
button.sendActions(for: .touchUpInside)
break
}
}
airplayVolume.removeFromSuperview()
}
Solution 3:[3]
I have modified Max's answer to my needs and thought it could be useful to share. It adapts to the superview with autolayout and has a method to call its action.
import SwiftUI
import AVKit
struct AirPlayView: UIViewRepresentable {
private let routePickerView = AVRoutePickerView()
func makeUIView(context: UIViewRepresentableContext<AirPlayView>) -> UIView {
UIView()
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<AirPlayView>) {
routePickerView.tintColor = .white
routePickerView.activeTintColor = .systemPink
routePickerView.backgroundColor = .clear
routePickerView.translatesAutoresizingMaskIntoConstraints = false
uiView.addSubview(routePickerView)
NSLayoutConstraint.activate([
routePickerView.topAnchor.constraint(equalTo: uiView.topAnchor),
routePickerView.leadingAnchor.constraint(equalTo: uiView.leadingAnchor),
routePickerView.bottomAnchor.constraint(equalTo: uiView.bottomAnchor),
routePickerView.trailingAnchor.constraint(equalTo: uiView.trailingAnchor)
])
}
func showAirPlayMenu() {
for view: UIView in routePickerView.subviews {
if let button = view as? UIButton {
button.sendActions(for: .touchUpInside)
break
}
}
}
}
You can still use it directly as a view, as in Max's answer, but also you can embed it in another view like a button and trigger the menu by hand, like I needed to:
@State private var airPlayView = AirPlayView()
var body: some View {
VStack {
// other views
Button(action: {
// other actions
airPlayView.showAirPlayMenu()
}) {
HStack {
Text("Show AirPlay menu")
Spacer()
airPlayView
.frame(width: 32, height: 32)
}
}
.buttonStyle(PlainButtonStyle())
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Max |
| Solution 2 | HatsuneMiku |
| Solution 3 |
