如何显示 AirPlay 菜单 SwiftUI
How to display the AirPlay Menu SwiftUI
多亏了airplay audio systemName emoji 我做了一个漂亮的图标
Button(action: {
showAirplay()
}, label: {
Image(systemName: "airplayaudio")
.imageScale(.large)
})
func showAirplay() {
???
}
但我不知道如何显示著名的菜单:
最后我自己解决了:D
正如评论中所说,我必须 "embed it inside" UIKit 并在 SwiftUI
中使用它
首先:
struct AirPlayButton: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<AirPlayButton>) -> UIViewController {
return AirPLayViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<AirPlayButton>) {
}
}
然后经典 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
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)
}
}
}
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()
}
为 SwiftUI 包装 AirPlay UIView 似乎是最好和最简单的解决方案。
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) {
}
}
用法:
VStack {
AirPlayView()
}
我已经根据自己的需要修改了 并且认为它可能对分享有用。它通过自动布局适应超级视图,并有一个方法来调用它的动作。
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
}
}
}
}
您仍然可以像 Max 的回答那样直接将它用作视图,但您也可以将它像按钮一样嵌入到另一个视图中并手动触发菜单,就像我需要的那样:
@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())
}
}
多亏了airplay audio systemName emoji 我做了一个漂亮的图标
Button(action: {
showAirplay()
}, label: {
Image(systemName: "airplayaudio")
.imageScale(.large)
})
func showAirplay() {
???
}
但我不知道如何显示著名的菜单:
最后我自己解决了:D 正如评论中所说,我必须 "embed it inside" UIKit 并在 SwiftUI
中使用它首先:
struct AirPlayButton: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<AirPlayButton>) -> UIViewController {
return AirPLayViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<AirPlayButton>) {
}
}
然后经典 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
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)
}
}
}
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()
}
为 SwiftUI 包装 AirPlay UIView 似乎是最好和最简单的解决方案。
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) {
}
}
用法:
VStack {
AirPlayView()
}
我已经根据自己的需要修改了
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
}
}
}
}
您仍然可以像 Max 的回答那样直接将它用作视图,但您也可以将它像按钮一样嵌入到另一个视图中并手动触发菜单,就像我需要的那样:
@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())
}
}