SwiftUI:允许用户通过按按钮启用画中画(iOS)

Dav*_*ese 5 ios swift avkit picture-in-picture swiftui

我正在设计一个应用程序,允许用户在 SwiftUI 视图中观看特定视频。我想支持 PiP,AVPictureInPictureController.isPictureInPictureSupported() 始终返回 true,而 pipController.isPictureInPicturePossible 有时返回 true,但通常在视频实际播放时不会返回 true。我可能误解了如何使用 AVPictureInPictureController。

我的应用程序使用以下代码初始化一个称为 FullScreenVideoView 的视图:

init(player: KHKVideoPlayer, aspectRatio: CGFloat, presentingViewController pvc: UIViewController?) {
    self.aspectRatio = aspectRatio
    self.pvc = pvc
    self.model = FullScreenVideoViewerModel(player: player)
    self.playerController = KHKPlayerController(player: player.avPlayer, cornerRadius: 0)
    
    if AVPictureInPictureController.isPictureInPictureSupported() {
        self.pipController = AVPictureInPictureController(playerLayer: AVPlayerLayer(player: player.avPlayer))!
    }
    
    self.isMuted = player.avPlayer.isMuted
}
Run Code Online (Sandbox Code Playgroud)

然后,在视图主体内,它通过调用初始化程序中定义的playerController来显示视频:

playerController
                    .frame(height: aspectRatio * geometry.size.width)
                    .onTapGesture {
                        if self.model.player.avPlayer.isPlaying {
                            self.model.pause()
                        } else {
                            self.model.play()
                        }
                    }
Run Code Online (Sandbox Code Playgroud)

PlayerController 是 AVPlayerViewController 的包装器:

struct KHKPlayerController: UIViewControllerRepresentable {
typealias UIViewControllerType = AVPlayerViewController

var player: AVPlayer
var cornerRadius: CGFloat?

init(player: AVPlayer) {
    self.player = player
}

init(player: AVPlayer, cornerRadius: CGFloat) {
    self.player = player
    self.cornerRadius = cornerRadius
}

func makeUIViewController(context: Context) -> AVPlayerViewController {
    let playerVC = AVPlayerViewController()
    playerVC.showsPlaybackControls = false
    playerVC.player = player
    playerVC.view.layer.masksToBounds = true
    playerVC.view.layer.cornerRadius = cornerRadius ?? 8
    return playerVC
}

func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
}
Run Code Online (Sandbox Code Playgroud)

}

应该有一个按钮来启动画中画:

RectangleButton(action: {
                                print("pip is possible: \(pipController?.isPictureInPicturePossible ?? false)")
                                pipController?.startPictureInPicture()
                            }, imageSystemName: "pip.enter", foregroundColor: UI.Constants.primaryColor, backgroundColor: UI.Constants.tertiaryColor, width: 35, height: 25, cornerRadius: 3)
Run Code Online (Sandbox Code Playgroud)

任何帮助将非常感激。我找不到任何有关在 SwiftUI 中启动 PiP 的有用信息。

注意 - 启用了正确的后台功能。另外,在我的 AppDelegate didFinishLaunchingWithOptions 方法中,我有以下代码似乎是 PiP 所需的:

do {
        try audioSession.setCategory(AVAudioSession.Category.playback)
    } catch  {
        print("Audio session failed")
    }
Run Code Online (Sandbox Code Playgroud)

iKK*_*iKK 3

你的代码实际上大部分工作 - 至少在我的 SwiftUI 代码中我几乎有与你描述的相同的步骤。

然而,我在playerLayer上做了更多的事情,也许这会导致pipController真正工作。

这是我在视图定义中对playerLayer 所做的操作,我将其添加为单独的控制层:

player = AVPlayer(url: url)
playerLayer = AVPlayerLayer()

playerLayer.player = player
layer.addSublayer(playerLayer)
        
playerLayer.videoGravity = .resizeAspect
playerLayer.frame = self.bounds

if let playerLayer = playerLayer {
    if AVPictureInPictureController.isPictureInPictureSupported() {
        pipController = AVPictureInPictureController(playerLayer: playerLayer)!
    }
}
Run Code Online (Sandbox Code Playgroud)

我不能 100% 确定这个额外的子层是否真的导致 pipController 得到改进。

另外,我没有使用KHKVideoPlayer而是使用普通的AVPlayer(url: url).

AVPlayerViewController自从在 SwiftUI 中完成所有操作以来,我根本没有使用过。

当然,我还添加了后台模式以使 pip 成为可能......

在此输入图像描述