SwiftUI:使用 ImagePickerController 从设备加载视频后如何正确编码 AVPlayer?

2023-12-26

我使用 SwiftUI 创建了一个视频播放器,它使用 imagePickerController 加载视频,然后假设从设备检索后播放视频。我发现检索视频后视频播放器不刷新。我不确定如何提供刷新它所需的适当的 @State|@Binding 。

我学习了如何使用可用的在线资源编写视频播放器代码。我找到了一种从我的设备加载视频并将其加载到我的视频播放器的方法。但是,当我按下播放按钮时,加载视频后,只播放声音。我尝试将视频播放器设置为 @State|@Binding 但找不到解决方案,因为它似乎不是直观地这样做的。

谁能建议如何使用 SwiftUI 更新视频播放器的代码?

P.S.1)您必须使用实际设备来加载视频; 2) 滑块尚未工作。接下来我会继续努力。

披露:

我从在线资源中改编了此代码。 这项工作大部分的原始源代码可以在以下链接找到:

如何在 SwiftUI 中打开 ImagePicker? https://stackoverflow.com/questions/56515871/how-to-open-the-imagepicker-in-swiftui

https://www.raywenderlich.com/5135-how-to-play-record-and-merge-videos-in-ios-and-swift https://www.raywenderlich.com/5135-how-to-play-record-and-merge-videos-in-ios-and-swift

https://medium.com/@chris.mash/avplayer-swiftui-part-2-player-controls-c28b721e7e27 https://medium.com/@chris.mash/avplayer-swiftui-part-2-player-controls-c28b721e7e27

import SwiftUI
import AVKit
import PhotosUI
import MobileCoreServices

struct ContentView: View {

    @State var showImagePicker: Bool = false
    @State var url: URL?

    var body: some View {
        ZStack {
            VStack {
                Button(action: {
                    withAnimation {
                        self.showImagePicker.toggle()
                    }
                }) {
                    Text("Show image picker")
                }

                // The video player will needs to be a @State??? as it is not updated with UIView changes but works when no view changes occur.
                PlayerContainerView(player: AVPlayer(url: url ?? URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!))
            }

            if (showImagePicker) {
                ImagePicker(isShown: $showImagePicker, url: $url)
            }
        }
    }
}

struct PlayerView: UIViewRepresentable {
    let player: AVPlayer
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
    }
    func makeUIView(context: Context) -> UIView {
        return PlayerUIView(player: player)
    }
}

class PlayerUIView: UIView {
    private let playerLayer = AVPlayerLayer()
    init(player: AVPlayer) {
        super.init(frame: .zero)

        playerLayer.player = player
        layer.addSublayer(playerLayer)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }
}

struct PlayerContainerView : View {

    @State var seekPos = 0.0

    private let player: AVPlayer
    init(player: AVPlayer) {
        self.player = player
    }
    var body: some View {
        VStack {
            PlayerView(player: player)
            PlayerControlsView(player: player)
        }
    }
}

struct PlayerControlsView : View {
    @State var playerPaused = true
    @State var seekPos = 0.0
    let player: AVPlayer
    var body: some View {
        HStack {
            Button(action: {
                self.playerPaused.toggle()
                if self.playerPaused {
                    self.player.pause()
                }
                else {
                    self.player.play()
                }
            }) {
                Image(systemName: playerPaused ? "play" : "pause")
                    .padding(.leading, 20)
                    .padding(.trailing, 20)
            }
            Slider(value: $seekPos, from: 0, through: 1, onEditingChanged: { _ in
                guard let item = self.player.currentItem else {
                    return
                }

                let targetTime = self.seekPos * item.duration.seconds
                self.player.seek(to: CMTime(seconds: targetTime, preferredTimescale: 600))
            })
                .padding(.trailing, 20)
        }
    }
}

struct ImagePicker: UIViewControllerRepresentable {

    @Binding var isShown: Bool
    @Binding var url: URL?

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

        @Binding var isShown: Bool
        @Binding var url: URL?

        init(isShown: Binding<Bool>, url: Binding<URL?>) {
            $isShown = isShown
            $url = url
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

            let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
            guard let mediaType = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaType)] as? String,
                mediaType == (kUTTypeMovie as String),
                let uiURL = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaURL)] as? URL
                else { return }

            url = uiURL
            isShown = false
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            isShown = false
        }

    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(isShown: $isShown, url: $url)
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.mediaTypes = [kUTTypeMovie as String]
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController,
                                context: UIViewControllerRepresentableContext<ImagePicker>) {
    }
}

fileprivate func convertFromUIImagePickerControllerInfoKeyDictionary(_ input: [UIImagePickerController.InfoKey: Any]) -> [String: Any] {
    return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
}

fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
    return input.rawValue
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView(showImagePicker: true)
    }
}
#endif

视频播放器没有按预期播放视频,它只播放声音,表明它正在播放视频;但是,我看不到它正在播放。它仍然是一个黑匣子。

UPDATE:以下是完全编辑的代码,可以按预期工作(滑块除外),在下面的评论中得到了回答:

import SwiftUI
import AVKit
import PhotosUI
import MobileCoreServices

struct ContentView: View {

    @State var showImagePicker: Bool = false
    @State var url: URL?

    var body: some View {
        ZStack {
            VStack {
                Button(action: {
                    withAnimation {
                        self.showImagePicker.toggle()
                    }
                }) {
                    Text("Show image picker")
                }

                PlayerContainerView(player: AVPlayer(url: url ?? URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!))
            }

            if (showImagePicker) {
                ImagePicker(isShown: $showImagePicker, url: $url)
            }
        }
    }
}

struct PlayerView: UIViewRepresentable {
    let player: AVPlayer
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
        (uiView as? PlayerUIView)?.updatePlayer(player: player)
    }

    func makeUIView(context: Context) -> UIView {
        return PlayerUIView(player: player)
    }
}

class PlayerUIView: UIView {
    private let playerLayer = AVPlayerLayer()
    init(player: AVPlayer) {
        super.init(frame: .zero)

        playerLayer.player = player
        layer.addSublayer(playerLayer)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }

    func updatePlayer(player: AVPlayer) {
        self.playerLayer.player = player
    }
}

struct PlayerContainerView : View {

    @State var seekPos = 0.0

    private let player: AVPlayer
    init(player: AVPlayer) {
        self.player = player
    }
    var body: some View {
        VStack {
            PlayerView(player: player)
            PlayerControlsView(player: player)
        }
    }
}

struct PlayerControlsView : View {
    @State var playerPaused = true
    @State var seekPos = 0.0
    let player: AVPlayer
    var body: some View {
        HStack {
            Button(action: {
                self.playerPaused.toggle()
                if self.playerPaused {
                    self.player.pause()
                }
                else {
                    self.player.play()
                }
            }) {
                Image(systemName: playerPaused ? "play" : "pause")
                    .padding(.leading, 20)
                    .padding(.trailing, 20)
            }
            Slider(value: $seekPos, from: 0, through: 1, onEditingChanged: { _ in
                guard let item = self.player.currentItem else {
                    return
                }

                let targetTime = self.seekPos * item.duration.seconds
                self.player.seek(to: CMTime(seconds: targetTime, preferredTimescale: 600))
            })
                .padding(.trailing, 20)
        }
    }
}

struct ImagePicker: UIViewControllerRepresentable {

    @Binding var isShown: Bool
    @Binding var url: URL?

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

        @Binding var isShown: Bool
        @Binding var url: URL?

        init(isShown: Binding<Bool>, url: Binding<URL?>) {
            _isShown = isShown
            _url = url
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

            let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
            guard let mediaType = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaType)] as? String,
                mediaType == (kUTTypeMovie as String),
                let uiURL = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaURL)] as? URL
                else { return }

            url = uiURL
            isShown = false
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            isShown = false
        }

    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(isShown: $isShown, url: $url)
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.mediaTypes = [kUTTypeMovie as String]
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController,
                                context: UIViewControllerRepresentableContext<ImagePicker>) {
    }
}

fileprivate func convertFromUIImagePickerControllerInfoKeyDictionary(_ input: [UIImagePickerController.InfoKey: Any]) -> [String: Any] {
    return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
}

fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
    return input.rawValue
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView(showImagePicker: true)
    }
}
#endif

您将 updateUIView 留空。你应该实现它:

func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
    (uiView as? PlayerUIView)?.updatePlayer(player: player)
}

并将以下方法添加到您的 PlayerUIView 中:

func updatePlayer(player: AVPlayer) {
    self.playerLayer.player = player
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SwiftUI:使用 ImagePickerController 从设备加载视频后如何正确编码 AVPlayer? 的相关文章

随机推荐

  • 使用 foreach 循环来初始化变量

    我构建了一个空关联数组 其键名引用提交的帖子数据 我可以很好地捕获后数据 但在尝试实例化名称与数组键匹配的变量时遇到了麻烦 例如 insArray array rUsername gt rPass gt rQuestion gt rAnsw
  • 永久修改启动 Activity 的 Intent

    我想发送一个意图来启动一个活动 我希望能够修改该意图 然后 当活动被销毁并重新创建时 我希望当我调用时这些修改仍然存在getIntent 目前 只要 Activity 没有被销毁 修改意图就可以正常工作 如果有 那么当重新创建 Activi
  • 根据拖放位置对 firestore 中的文档进行排序

    我的目标是呈现我的LinkContainer组件 以便它们位于我的拖放上下文中
  • 如何修复 MSSQL 上的“无效列名”SQL 异常

    我试图在运行时传递要在代码中检查的列名称和值 不过我得到的是 无效的列名 例外 代码如下 cmd new SqlCommand con Open cmd Connection con cmd CommandText INSERT INTO
  • ASP.NET MVC3 RC2 不工作

    我的输入装饰如下
  • 如何获取 Java Hashmap 上冲突数量的指标?

    我正在实现一个自定义哈希函数 如果我在 HashMap 存储桶中发生多次冲突 我如何知道存储桶中存储了多少元素 API 中没有对此直接支持 成员变量table用于存储存储桶的 甚至不是公共的 因此扩展该类不会让您走得太远 假设您正在评估哈希
  • 从数据列表中选择项目时,为什么值末尾的空格会消失?

    我遇到了一个奇怪的问题 当使用数据列表时 值末尾的空格消失了 这让我想知道为什么 我使用的是谷歌浏览器 我可以确保末尾的空格将包含在 通过将最终结果分配给值属性 而不是介于
  • CSS中first-line和first-child的特殊性?

    我有以下 html 代码 p asdasdasdsad br sdfsdfs p 输出是 asdasdasdasd sdfsdfs 但是 我的想法是 p 标签是 body 的第一个子标签 first child 是一个伪类 其特异性为 10
  • $authWithPassword 不是 AngularFire 2.x 中的函数

    我以前看过有关此问题的帖子 但它们要么已经过时 要么提供与我的设置非常相似的解决方案 基本上 我的控制器中有两个函数 authCtrl login 和 authCtrl register 寄存器对 Auth createUserWithEm
  • javascript 相当于 java 的 Map.getKey()

    我有一个地图 或者说 JavaScript 中的关联数组类型的结构 var myMap one 1 two 2 three 3 要获取与给定值相对应的键 我必须迭代映射 function map test value var myMap o
  • 删除 Mac 上的 Qt 库

    我想删除已安装的 Qt 4 8 库并在我的 Mac 上安装 Qt 4 6 库 但是当我尝试安装它们时 我得到 Qt 库无法安装在此磁盘上 较新版本的 该软件已存在于该磁盘上 我删除了 usr local Qt4 8 x文件夹 但消息仍然存在
  • Rmd 文件中的 knit_child 正在打印不需要的输出

    我已经成功使用了knit child生成pdf文件 遵循以下代码http yihui name knitr demo child http yihui name knitr demo child 但是当我尝试在 Rmd file r res
  • 如何将复杂的 T-SQL 转换为 Linq

    我正在使用 EntityFramework Core 2 0 从事 Asp NET Core 2 0 项目 我正在尝试将现有的遗留 SQL 存储过程转换为 EntityFramework Core 中的 Linq 但我在处理 T SQL 的
  • 何时使用抽象语法树或具体语法树?

    我一直在研究编译器 词法分析器似乎非常简单 取一个 句子 并将其分解为单词 或标记 为了确保语法正确 需要解析器 解析器通常采用标记并构建一棵树 该树产生根节点 单词到句子 段落 页面等 From 这个问题 https stackoverf
  • 取消部分CSS样式

    对于一个项目 我必须使用定义的样式表 我无法编辑它 我必须接受它 但是 有些样式不适合该网站 例如边距 我也创建了自己的 CSS 文件来覆盖其中一些属性 举个例子 如果我有这个 div class container My test tex
  • 为什么这个将字符串转换为整数的 Golang 代码会失败?

    这应该很简单 strconv Atoi 1250000 0000 这会导致错误 0 strconv ParseInt 解析 1250000 0000 语法无效 有什么线索吗 Atoi仅适用于可以解析为整数的字符串 你需要的是解析浮点型 ht
  • 一台视频混合渲染器 9 (VMR9) 可以渲染更多视频流吗?

    我使用相同数量的 VMR9 实例以 Windows 形式渲染多个视频流 我使用 DirectShowLib 2005 在 C 中执行此操作 如果需要显示 100 个视频 我将创建 100 个 FilterGraph IFilterGraph
  • 在 WooCommerce 中随处保存并显示产品选择的自定义数据

    我有一个代码显示产品编辑页面上的复选框 当我单击此复选框时 单个产品页面上会显示一个选择框 这是我的代码 Display Checkbox Field add action woocommerce product options gener
  • 如何使用 JFileChooser 将文件保存到所选目录

    我是 Java 新手 所以请耐心等待 在我的程序中 我想让用户能够将文件保存到他们选择的目录中 经过一番研究后 我发现了这个名为 JFileChooser 的漂亮类 我想要做的是允许用户通过 JFileChooser GUI 转到所需的目录
  • SwiftUI:使用 ImagePickerController 从设备加载视频后如何正确编码 AVPlayer?

    我使用 SwiftUI 创建了一个视频播放器 它使用 imagePickerController 加载视频 然后假设从设备检索后播放视频 我发现检索视频后视频播放器不刷新 我不确定如何提供刷新它所需的适当的 State Binding 我学