#ios #swift #macos #swiftui
#iOS #swift #macos #swiftui
Вопрос:
У меня есть следующий VStack, который содержит AVPlayer (в PlayerView):
struct ContentView: View {
@State var url: URL?
private let openFile = NotificationCenter.default.publisher(for: .openFile)
var body: some View {
VStack {
if isVideo(self.url!) {
PlayerView(url: self.url!)
} else {
Image(nsImage: NSImage(contentsOf: self.url!)!).resizable().aspectRatio(contentMode: .fit)
}
}.onReceive(openFile) { notification in
self.url = notification.object as? URL
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
И это PlayerView:
struct PlayerView: NSViewRepresentable {
private var url: URL
init(url: URL) {
self.url = url
}
func updateNSView(_ nsView: PlayerNSView, context _: NSViewRepresentableContext<PlayerView>) {
nsView.play(url: url)
}
func makeNSView(context _: Context) -> PlayerNSView {
PlayerNSView(frame: .zero)
}
func dismantleNSView(coordinator _: Coordinator) {
// not called
}
}
После обновления с видео на изображение аудио видео продолжает воспроизводиться в течение нескольких секунд.
Где я могу указать AVPlayer на паузу? Уведомляет ли VStack видеоплеер?
Обновлено с помощью кода из iUrii:
struct ContentView: View {
@State var url: URL?
@State var playerView: PlayerView?
private let openFile = NotificationCenter.default.publisher(for: .openFile)
var body: some View {
VStack {
if let view = playerView {
view
} else {
Image(nsImage: NSImage(contentsOf: self.url!)!).resizable().aspectRatio(contentMode: .fit)
}
}.onReceive(openFile) { notification in
url = notification.object as? URL
if playerView != nil {
playerView!.player.pause()
playerView = nil
}
if videoExtensions.contains(url!.pathExtension.lowercased()) {
playerView = PlayerView(url: url!)
}
}
}
}
Это отлично работает при переходе от видео к изображению к видео.
Когда я переключаюсь с видео на видео, первое видео будет приостановлено, а аудио из второго видео начнет воспроизводиться, хотя оно не отображается (первое видео все еще видно).
Я решил это, обновив проигрыватель playerView.player.replaceCurrentItem(with: playerItem)
вместо замены представления.
Комментарии:
1.
dismantleNSView(_:coordinator:)
это статическая функция в NSViewRepresentable (по крайней мере, сейчас!), Которая, возможно, и была причиной того, что она не была вызвана.
Ответ №1:
Вы должны управлять своим PlayerNSView
с AVPlayer
помощью вручную, если хотите контролировать его поведение, например:
struct PlayerView: NSViewRepresentable {
let player: AVPlayer
init(url: URL) {
self.player = AVPlayer(url: url)
}
func updateNSView(_ nsView: AVPlayerView, context: NSViewRepresentableContext<Self>) {
}
func makeNSView(context: NSViewRepresentableContext<Self>) -> AVPlayerView {
let playerView = AVPlayerView(frame: .zero)
playerView.player = player
return playerView
}
}
struct ContentView: View {
@State var playerView: PlayerView?
var body: some View {
VStack {
if let view = playerView {
view
} else {
Image(nsImage: NSImage(named: "iphone12")!)
}
Button("Toogle") {
if playerView == nil {
let url = URL(string: "https://www.apple.com/105/media/us/iphone-12-pro/2020/e70ffbd8-50f1-40f3-ac36-0f03a15ac314/films/product/iphone-12-pro-product-tpl-us-2020_16x9.m3u8")!
playerView = PlayerView(url: url)
playerView?.player.play()
}
else {
playerView?.player.pause()
playerView = nil
}
}
}
}
}