在SwiftUI/AVPlayer中与NotificationCenter/Combine搏斗
当物品播放完毕时,我试图暂停我的AVPlayer。使用SwiftUI执行此操作的最佳方法是什么?我不太了解通知,在哪里声明它们,等等。有没有一种方法可以使用Combine来实现这一点?示例代码将非常棒!先谢谢你 更新: 在下面答案的帮助下,我成功地创建了一个类,该类接受AVPlayer并在项目结束时发布通知。您可以使用以下内容订阅通知: 类别:在SwiftUI/AVPlayer中与NotificationCenter/Combine搏斗,swift,swiftui,avplayer,combine,notificationcenter,Swift,Swiftui,Avplayer,Combine,Notificationcenter,当物品播放完毕时,我试图暂停我的AVPlayer。使用SwiftUI执行此操作的最佳方法是什么?我不太了解通知,在哪里声明它们,等等。有没有一种方法可以使用Combine来实现这一点?示例代码将非常棒!先谢谢你 更新: 在下面答案的帮助下,我成功地创建了一个类,该类接受AVPlayer并在项目结束时发布通知。您可以使用以下内容订阅通知: 类别: import Combine import AVFoundation class PlayerFinishedObserver { let
import Combine
import AVFoundation
class PlayerFinishedObserver {
let publisher = PassthroughSubject<Void, Never>()
init(player: AVPlayer) {
let item = player.currentItem
var cancellable: AnyCancellable?
cancellable = NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime, object: item).sink { [weak self] change in
self?.publisher.send()
print("Gotcha")
cancellable?.cancel()
}
}
}
订阅某些视图:
.onReceive(finishedObserver.publisher) {
print("Gotcha!")
}
我为类似问题找到了一个解决方案:
AVPlayer
的新子类李>
observeValue
,当玩家到达结束时间时为当前物品添加观察者李>
以下是简化的示例:
为播放器导入AVKit//
导入Combine//以观察并添加为环境对象
末级音频播放器:AVPlayer,ObservieObject{
var songDidEnd=PassthroughSubject()//您可以在某些视图中与.onReceive函数一起使用它
重写init(){
super.init()
registerObserves()
}
专用函数注册表观测值(){
addObserver(self,forKeyPath:“currentItem”,选项:[.new],上下文:nil)
//使用示例
}
重写func observeValue(forKeyPath keyPath:String?,对象的类别:Any?,更改:[NSKeyValueChangeKey:Any]?,上下文:UnasFemeutableRawPointer?){
//播放器中的currentItem可能为零。我将observer添加到exist项中
如果keyPath==“currentItem”,则让item=currentItem{
NotificationCenter.default.addObserver(self,选择器:#选择器(playerIDfinishPlaying(:)),名称:NSNotification.name.AVPlayerItemDidPlayToEndTime,对象:item)
//另一种方法,使用联合收割机
var可取消:任何可取消?
Cancelable=NotificationCenter.default.publisher(用于:.AVPlayerItemDidPlayToEndTime,对象:item)。接收{[weak self]\uIn
self?.songdiden.send()
可取消?.cancel()
}
}
//其他观察员
}
@objc专用func播放器IDfinishPlaying(uuu通知:通知){
playNextSong()//我的实现,在这里您可以写:“self.pause()”
}
}
更新:使用.onReceive
的简单示例(请注意,我在编写时没有使用/Xcode,因此可能会有错误):
struct ContentView:View{
@EnvironmentObject var audioPlayer:audioPlayer
@国家机密var someText:String=“正在播放歌曲”
var body:一些观点{
文本(someText)
.onReceive(self.audioPlayer.songdiden){//也许您需要在这里输入“uu”
self.handleSongDidEnd()
}
}
私有函数handleSongDidEnd(){
打印(“歌曲结束了”)
动画片{
someText=“歌曲暂停”
}
}
}
关于将
与AVPlayer
组合:您可以查看我的,在那里您将看到一些观察播放时间的方法以及使用SwiftUI中的滑块回放时间的功能
我正在使用一个AudioPlayer
实例,控制播放/暂停功能或更改currentItem
(这意味着设置另一首歌曲),如下所示:
class SceneDelegate:UIResponder,UIWindowSceneDelegate{
//其他工作人员
func场景(场景:UIScene,willConnectTo会话:UISceneSession,选项connectionOptions:UIScene.connectionOptions){
让homeView=ContentView()
.environmentObject(AudioPlayer())
//SceneDelegate的其他工作人员
}
}
非常感谢!我很快就会试试的。你知道有没有办法使用更像这样的东西?NotificationCenter.default.publisher(用于:.AVPlayerItemDidPlayToEndTime),然后使用。(onReceive:)响应?我想知道是否有办法避免@objc。我的很多AVPlayer函数都在我的SwiftUI视图中,它不允许我在那里使用objc,因为它是一个结构。或者我应该将函数移到AudioPlayer is class中吗?@StormTrooper您可以在@objc
函数中更改一些发布者
,例如songdiden.send()
(您需要创建让songdiden=PassthroughSubject()
)。因此,您可以像往常一样使用.onReceive
。关于NotificationCenter.default.publisher(用于:.AVPlayerItemDidPlayToEndTime)
-很有趣,也许我会尝试使用它。但是不,我不知道这样做,所以我不能说,在这个重要时刻它是否有效,谢谢。我会把它弄得一团糟,然后再打给你。非常感谢您的帮助。@StormTrooper,您的想法是对的,您可以编写以下内容:NotificationCenter.default.publisher(for:.AVPlayerItemDidPlayToEndTime,object:item)
而不是我的变体。谢谢你的想法)@StormTrooper我更新了代码片段,下面是你想法的例子。我没有测试,但你可以试试。看来会奏效的
.onReceive(finishedObserver.publisher) {
print("Gotcha!")
}