我正在努力实现一个用AVKit制作的动态视频播放器中的点击手势.我打算让视频在提要(这是一个社交媒体应用程序)中观看时,视频在没有声音的情况下播放.点击一次视频就会有声音,点击两次视频就会全屏显示.

目前,单塔工程.但是,除非我点击视频的右上角,否则不会检测到双击.

import SwiftUI
import AVKit

struct VideoPlayerView: View {
    
    @StateObject private var viewModel: VideoPlayerViewModel
    
    init(url: URL, isFeedView: Bool = true) {
        _viewModel = StateObject(wrappedValue: .init(url: url, isFeedView: isFeedView))
    }
    
    var body: some View {
        ZStack {
            if let player: AVPlayer = viewModel.player {
                VideoPlayer(player: player)
                    .onAppear {
                        // Start playing or resume from the last known position if in feed view
                        if viewModel.isFeedView {
                            if let lastKnownTime = viewModel.lastKnownTime {
                                player.seek(to: CMTime(seconds: lastKnownTime, preferredTimescale: 600))
                            }
                            player.play()
                            player.volume = 0 // Set volume to 0 for feed view
                        }
                    }
                    .onDisappear {
                        // Pause the video and store the last known time
                        viewModel.lastKnownTime = player.currentTime().seconds
                        player.pause()
                    }
                    .contentShape(Rectangle())
                    .gesture(TapGesture(count: 2).onEnded {
                        print("Double tap detected")
                        viewModel.isFullScreen.toggle()
                    })
                    .simultaneousGesture(TapGesture().onEnded {
                        print("Single tap detected")
                        player.volume = 1 // Set volume to 1
                    })
            }
        }
        .maxSize()
        .fullScreenCover(isPresented: $viewModel.isFullScreen) {
            AVPlayerViewControllerRepresented(viewModel: viewModel)
        }
    }
}

class VideoPlayerViewModel: ObservableObject {
    @Published var player: AVPlayer?
    @Published var lastKnownTime: Double?
    @Published var isFullScreen: Bool = false
    @Published var isFeedView: Bool
    
    init(url: URL, isFeedView: Bool = true) {
        player = AVPlayer(url: url)
        lastKnownTime = nil
        self.isFeedView = isFeedView
        if isFeedView {
            registerForPlaybackEndNotification()
        }
    }
    
    private func registerForPlaybackEndNotification() {
        NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil) { [weak self] _ in
            self?.videoDidFinish()
        }
    }
    
    private func videoDidFinish() {
        // Replay logic for feed view
        if isFeedView, let player = player {
            player.seek(to: .zero)
            player.play()
        }
    }
}

我目前的手势代码是基于this的,但我希望能够扩大可检测区域,这样当我在视频上的任何地方双击时,它就会进入全屏.我读到.contentShape(Rectangle())应该做到这一点,但到目前为止还没有奏效.我遗漏了什么?

推荐答案

您可以try 使用透明的.overlay来捕获taps.

struct ContentView: View {
    let urlTest = "https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4"
    var body: some View {
        if let url = URL(string: urlTest) {
            VideoPlayerView(url: url)
        }
    }
}

struct VideoPlayerView: View {
    @StateObject private var viewModel: VideoPlayerViewModel
    
    init(url: URL, isFeedView: Bool = true) {
        _viewModel = StateObject(wrappedValue: .init(url: url, isFeedView: isFeedView))
    }
    
    var body: some View {
        ZStack {
            if let player: AVPlayer = viewModel.player {
                VideoPlayer(player: player)
                    .onAppear {
                        // Start playing or resume from the last known position if in feed view
                        if viewModel.isFeedView {
                            if let lastKnownTime = viewModel.lastKnownTime {
                                player.seek(to: CMTime(seconds: lastKnownTime, preferredTimescale: 600))
                            }
                            player.play()
                            player.volume = 0 // Set volume to 0 for feed view
                        }
                    }
                    .onDisappear {
                        // Pause the video and store the last known time
                        viewModel.lastKnownTime = player.currentTime().seconds
                        player.pause()
                    }
                    .overlay { // <--- here
                        Color.white.opacity(0.0001)
                            .ignoresSafeArea() // <--- adjust as needed
                            .onTapGesture(count: 2) {
                                print("--->  Double tap detected")
                                viewModel.isFullScreen.toggle()
                            }
                            .onTapGesture(count: 1) {
                                print("--->  Single tap detected")
                                player.volume = 1 // Set volume to 1
                            }
                    }
            }
        }
        // .maxSize()
        .fullScreenCover(isPresented: $viewModel.isFullScreen) {
            // AVPlayerViewControllerRepresented(viewModel: viewModel)
            Button("dismiss") {  // <-- for testing
                viewModel.isFullScreen = false
            }
        }
    }
}

Ios相关问答推荐

删除领域中的cartItem时出现问题

在SwiftUI中为圆角矩形创建均匀分布的点轮廓

SWIFT AVFoundation翻转相机功能不起作用

在SwiftUI中插入绘制重复形状

由于已存在同名项目,因此无法将Mapbox.xcframework-ios.sign复制到Signature中

如何在KMM项目中处理PHPickerViewController的回调?

CIKernel的Metal Shader裁剪问题

iOS应用程序冻结在UICollectionView代码,但我没有';没有任何UICollectionViews

SwiftData共享扩展阻止应用程序打开SQLite文件

在最新版本的 iOS 中,设备上的Localized.strings文件发生了什么变化?

iOS - 判断开发者模式是否开启 (Swift)

Swift Combine 防止初始值触发接收器并同时防止重复?

如何在 SwiftUI 中创建显示当前电池电量的电池徽章

通过 Rosetta 打开模拟器 xcode 14 以修复滚动

如何让替换视图淡入旧视图而不是交叉淡入淡出?

如何在 SwiftUI 中只显示一次随机数组的项目?

在 iPad 上删除列表的顶部和底部行

iOS 中的 Crashlytics 不会继续通过 Fabric 应用程序中的构建您的项目

如何更改uitableview删除按钮文本

AFNetworking 发布请求