【问题标题】:How to display the AirPlay Menu SwiftUI如何显示 AirPlay 菜单 SwiftUI
【发布时间】:2020-05-21 14:13:24
【问题描述】:

感谢airplay音频系统名字表情符号我做了一个不错的图标

Button(action: {
        showAirplay()
}, label: {
    Image(systemName: "airplayaudio")
        .imageScale(.large)
})

func showAirplay() {
       ???
}

但我不知道如何显示著名的菜单:

【问题讨论】:

标签: ios swift swiftui ios13 airplay


【解决方案1】:

最后我自己解决了:D 正如评论中所说,我必须将其“嵌入”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 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)

        }
    }
}

【讨论】:

    【解决方案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()
      }
    

    【讨论】:

      【解决方案3】:

      为 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()
      }
      

      【讨论】:

        【解决方案4】:

        我已根据自己的需要修改了Max's answer,并认为分享它可能会很有用。它通过自动布局适应superview,并有一个方法来调用它的action。

        import SwiftUI
        import AVKit
        
        struct AirPlayView: UIViewRepresentable {
            
            private let routePickerView = AVRoutePickerView()
        
            let view = UIView()
            routePickerView.tintColor = .white
            routePickerView.activeTintColor = .accentColor
            
            routePickerView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(routePickerView)
        
            NSLayoutConstraint.activate([
                routePickerView.topAnchor.constraint(equalTo: view.topAnchor),
                routePickerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                routePickerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
                routePickerView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
            ])
            return view
        
            func updateUIView(_ uiView: UIView, context: 
            }
            
            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())
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-23
          • 2021-02-10
          相关资源
          最近更新 更多