SwiftUI 中的 MPMediaPickerController?
MPMediaPickerController in SwiftUI?
我正在 SwiftUI 重建我的一个应用程序,但我遇到了障碍。
我的问题是..我的应用程序是一个 AudioVisual 测试生成器,目前能够 select 用户设备音乐库中的测试歌曲,并将该歌曲设置为应用程序的测试歌曲.其他测试包括左扬声器、右扬声器等,但此功能允许用户 select 从他们设备的库中选择他们自己的自定义测试歌曲,(或者默认为默认测试歌曲。)
我的应用程序目前是用 Swift 编写的,并使用 MPMediaPickerController 来 select 这首歌,它工作得很好。但是,我真的很难让音乐库选择器控制器与我的 SwiftUI 重建一起工作。任何人都知道在 SwiftUI?
中访问用户音乐库的可靠方法
我一直被不符合 class 协议 'NSObjectProtocol' 的对象所困扰,这让我相信有更多的 SwiftUI-y 方式来做到这一点?或者,也许我可以对我的大部分应用程序使用 SwiftUI,但过渡到歌曲 selection?
的 UIView
这里有一些代码还不能工作,但很漂亮。我只是尽我所能解决这个问题,并计划在我让它工作时进行重构。
//可能导入的东西比我需要的多。
import UIKit
import SwiftUI
import AVFoundation
import AVKit
import MediaPlayer
class SongPickerController: UIViewControllerRepresentable, MPMediaPickerControllerDelegate {
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIImagePickerController {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = context.coordinator
return imagePickerController
}
func makePickerController(context: Context) -> MPMediaPickerController {
var picker = MPMediaPickerController()
picker = MPMediaPickerController(mediaTypes: .anyAudio)
//picker.delegate = self
picker.allowsPickingMultipleItems = false
picker.showsCloudItems = false
picker.prompt = NSLocalizedString(Texts.pickerDetail, comment: Texts.pickerComment)
return picker
}
func songSelectButtonClicked () {
picker = MPMediaPickerController(mediaTypes: .anyAudio)
picker?.delegate = self
picker?.allowsPickingMultipleItems = false
picker?.showsCloudItems = false
picker?.prompt = NSLocalizedString(Texts.pickerDetail, comment: Texts.pickerComment)
self.present(picker!, animated: false, completion: nil)
func updateUIViewController(_ uiViewController: MPMediaPickerController, context: Context) {
}
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: SongPickerController
init(_ imagePickerController: SongPickerController) {
self.parent = imagePickerController
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)}}}}
struct SongUIView: UIViewController, MPMediaPickerControllerDelegate {
var picker: MPMediaPickerController?
func songSelectButtonClicked () {
picker = MPMediaPickerController(mediaTypes: .anyAudio)
picker?.delegate = self
picker?.allowsPickingMultipleItems = false
picker?.showsCloudItems = false
picker?.prompt = NSLocalizedString(Texts.pickerDetail, comment: Texts.pickerComment)
self.present(picker!, animated: false, completion: nil)
}
func mediaPicker(_ mediaPicker: MPMediaPickerController,
didPickMediaItems mediaItemCollection: MPMediaItemCollection){
let selectedSong = mediaItemCollection.items
if (selectedSong.count) > 0 {
let songItem = selectedSong[0]
let songURL = songItem.value(forProperty: MPMediaItemPropertyAssetURL)
let saveString = "\(songURL!)"
let saveTitle = "\(songItem.title!) by \(songItem.artist!)"
saveDefaultSong(saveString as NSString, title: saveTitle as NSString)
mediaPicker.dismiss(animated: true, completion: nil)
///selectSongButton.setTitle("Custom song assigned!", for: UIControl.State())
}
}
func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) {
mediaPicker.dismiss(animated: true, completion: nil)
}
func saveDefaultSong (_ name: NSString, title: NSString) {
UserDefaults.standard.set(name, forKey: "Default Song")
UserDefaults.standard.set(title, forKey: "Default Song Title")
}
}
UIViewControllerRepresentable
是 SwiftUI 视图,所以必须是一个结构
struct SongPickerController: UIViewControllerRepresentable
但是 UIViewController
是 UIKit class,所以继承的实体必须是 class
class SongUIView: UIViewController
在用户 Asperi 将我推向正确的方向后,我想分享我的最终代码以在 SwiftUI 中呈现音乐库。这是第一部分...
import SwiftUI
import MediaPlayer
//MUSIC PICKER.. WORKING
struct MusicPicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var song: Song?
class Coordinator: NSObject, UINavigationControllerDelegate, MPMediaPickerControllerDelegate {
var parent: MusicPicker
init(_ parent: MusicPicker) {
self.parent = parent
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MusicPicker>) -> MPMediaPickerController {
let picker = MPMediaPickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: MPMediaPickerController, context: UIViewControllerRepresentableContext<MusicPicker>) {
}
}
然后为了在我的 SwiftUI 视图中调用它,我声明了一对 @State 变量
@State private var song: Song?
@State private var showingSongPicker = false
并使用此按钮显示媒体选择器
Button(action: {
self.showingSongPicker = true
}
){
Text("Edit Test Song")
}
.sheet(isPresented: $showingSongPicker) {
MusicPicker(song: self.$song)
}
注意:我仍在处理一些 Apple Music Token 问题,新测试歌曲的选择还没有用。但是呈现音乐选择器的部分是关于这个问题的,现在正在工作。
此解决方案几乎完全基于 Dave 在 7 月 28 日的 post。之前的代码还没有办法选择歌曲并将其传递给视图。在下面的示例中,它将选定的歌曲传递给 @EnvironmentObject,但它可以像 Dave 所建议的那样轻松地与 @Binding 一起使用。
import SwiftUI
import MediaPlayer
struct MusicPicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var player: AudioPlayer
class Coordinator: NSObject, UINavigationControllerDelegate, MPMediaPickerControllerDelegate {
var parent: MusicPicker
init(_ parent: MusicPicker) {
self.parent = parent
}
func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
let selectedSong = mediaItemCollection.items
if (selectedSong.count) > 0 {
let songItem = selectedSong[0]
parent.setSong(song: songItem)
mediaPicker.dismiss(animated: true, completion: nil)
}
}
}
func setSong(song: MPMediaItem) {
player.setAudioTrack(song: song)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MusicPicker>) -> MPMediaPickerController {
let picker = MPMediaPickerController()
picker.allowsPickingMultipleItems = false
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: MPMediaPickerController, context: UIViewControllerRepresentableContext<MusicPicker>) {
}
}
我正在 SwiftUI 重建我的一个应用程序,但我遇到了障碍。
我的问题是..我的应用程序是一个 AudioVisual 测试生成器,目前能够 select 用户设备音乐库中的测试歌曲,并将该歌曲设置为应用程序的测试歌曲.其他测试包括左扬声器、右扬声器等,但此功能允许用户 select 从他们设备的库中选择他们自己的自定义测试歌曲,(或者默认为默认测试歌曲。)
我的应用程序目前是用 Swift 编写的,并使用 MPMediaPickerController 来 select 这首歌,它工作得很好。但是,我真的很难让音乐库选择器控制器与我的 SwiftUI 重建一起工作。任何人都知道在 SwiftUI?
中访问用户音乐库的可靠方法我一直被不符合 class 协议 'NSObjectProtocol' 的对象所困扰,这让我相信有更多的 SwiftUI-y 方式来做到这一点?或者,也许我可以对我的大部分应用程序使用 SwiftUI,但过渡到歌曲 selection?
的 UIView这里有一些代码还不能工作,但很漂亮。我只是尽我所能解决这个问题,并计划在我让它工作时进行重构。
//可能导入的东西比我需要的多。
import UIKit
import SwiftUI
import AVFoundation
import AVKit
import MediaPlayer
class SongPickerController: UIViewControllerRepresentable, MPMediaPickerControllerDelegate {
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIImagePickerController {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = context.coordinator
return imagePickerController
}
func makePickerController(context: Context) -> MPMediaPickerController {
var picker = MPMediaPickerController()
picker = MPMediaPickerController(mediaTypes: .anyAudio)
//picker.delegate = self
picker.allowsPickingMultipleItems = false
picker.showsCloudItems = false
picker.prompt = NSLocalizedString(Texts.pickerDetail, comment: Texts.pickerComment)
return picker
}
func songSelectButtonClicked () {
picker = MPMediaPickerController(mediaTypes: .anyAudio)
picker?.delegate = self
picker?.allowsPickingMultipleItems = false
picker?.showsCloudItems = false
picker?.prompt = NSLocalizedString(Texts.pickerDetail, comment: Texts.pickerComment)
self.present(picker!, animated: false, completion: nil)
func updateUIViewController(_ uiViewController: MPMediaPickerController, context: Context) {
}
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: SongPickerController
init(_ imagePickerController: SongPickerController) {
self.parent = imagePickerController
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)}}}}
struct SongUIView: UIViewController, MPMediaPickerControllerDelegate {
var picker: MPMediaPickerController?
func songSelectButtonClicked () {
picker = MPMediaPickerController(mediaTypes: .anyAudio)
picker?.delegate = self
picker?.allowsPickingMultipleItems = false
picker?.showsCloudItems = false
picker?.prompt = NSLocalizedString(Texts.pickerDetail, comment: Texts.pickerComment)
self.present(picker!, animated: false, completion: nil)
}
func mediaPicker(_ mediaPicker: MPMediaPickerController,
didPickMediaItems mediaItemCollection: MPMediaItemCollection){
let selectedSong = mediaItemCollection.items
if (selectedSong.count) > 0 {
let songItem = selectedSong[0]
let songURL = songItem.value(forProperty: MPMediaItemPropertyAssetURL)
let saveString = "\(songURL!)"
let saveTitle = "\(songItem.title!) by \(songItem.artist!)"
saveDefaultSong(saveString as NSString, title: saveTitle as NSString)
mediaPicker.dismiss(animated: true, completion: nil)
///selectSongButton.setTitle("Custom song assigned!", for: UIControl.State())
}
}
func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) {
mediaPicker.dismiss(animated: true, completion: nil)
}
func saveDefaultSong (_ name: NSString, title: NSString) {
UserDefaults.standard.set(name, forKey: "Default Song")
UserDefaults.standard.set(title, forKey: "Default Song Title")
}
}
UIViewControllerRepresentable
是 SwiftUI 视图,所以必须是一个结构
struct SongPickerController: UIViewControllerRepresentable
但是 UIViewController
是 UIKit class,所以继承的实体必须是 class
class SongUIView: UIViewController
在用户 Asperi 将我推向正确的方向后,我想分享我的最终代码以在 SwiftUI 中呈现音乐库。这是第一部分...
import SwiftUI
import MediaPlayer
//MUSIC PICKER.. WORKING
struct MusicPicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var song: Song?
class Coordinator: NSObject, UINavigationControllerDelegate, MPMediaPickerControllerDelegate {
var parent: MusicPicker
init(_ parent: MusicPicker) {
self.parent = parent
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MusicPicker>) -> MPMediaPickerController {
let picker = MPMediaPickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: MPMediaPickerController, context: UIViewControllerRepresentableContext<MusicPicker>) {
}
}
然后为了在我的 SwiftUI 视图中调用它,我声明了一对 @State 变量
@State private var song: Song?
@State private var showingSongPicker = false
并使用此按钮显示媒体选择器
Button(action: {
self.showingSongPicker = true
}
){
Text("Edit Test Song")
}
.sheet(isPresented: $showingSongPicker) {
MusicPicker(song: self.$song)
}
注意:我仍在处理一些 Apple Music Token 问题,新测试歌曲的选择还没有用。但是呈现音乐选择器的部分是关于这个问题的,现在正在工作。
此解决方案几乎完全基于 Dave 在 7 月 28 日的 post。之前的代码还没有办法选择歌曲并将其传递给视图。在下面的示例中,它将选定的歌曲传递给 @EnvironmentObject,但它可以像 Dave 所建议的那样轻松地与 @Binding 一起使用。
import SwiftUI
import MediaPlayer
struct MusicPicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var player: AudioPlayer
class Coordinator: NSObject, UINavigationControllerDelegate, MPMediaPickerControllerDelegate {
var parent: MusicPicker
init(_ parent: MusicPicker) {
self.parent = parent
}
func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
let selectedSong = mediaItemCollection.items
if (selectedSong.count) > 0 {
let songItem = selectedSong[0]
parent.setSong(song: songItem)
mediaPicker.dismiss(animated: true, completion: nil)
}
}
}
func setSong(song: MPMediaItem) {
player.setAudioTrack(song: song)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MusicPicker>) -> MPMediaPickerController {
let picker = MPMediaPickerController()
picker.allowsPickingMultipleItems = false
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: MPMediaPickerController, context: UIViewControllerRepresentableContext<MusicPicker>) {
}
}