You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中为AVPlayerViewController添加点击手势致控件失效的解决方法

解决SwiftUI中AVPlayerViewController手势冲突问题

问题原因

SwiftUI的.onTapGesture会在视图最上层添加手势识别器,直接拦截所有触摸事件,导致底层AVPlayerViewController的原生播放控件(比如播放/暂停按钮、进度条)无法响应触摸。

解决方案:在UIKit层级添加手势(推荐)

不在SwiftUI层面加手势,而是直接给AVPlayerViewController的视图添加UITapGestureRecognizer,并设置cancelsTouchesInView = false,这样既可以响应自定义点击,又不会阻止原生控件的触摸事件。

完整修改后的PlayerViewSUI代码

import SwiftUI
import AVKit

public struct PlayerViewSUI: UIViewControllerRepresentable {
    public let player: AVPlayer?
    public let showsPlaybackControls: Bool
    public var onTap: (() -> Void)?

    public init(player: AVPlayer?, showsPlaybackControls: Bool = true, onTap: (() -> Void)? = nil) {
        self.player = player
        self.showsPlaybackControls = showsPlaybackControls
        self.onTap = onTap
    }

    public func makeUIViewController(context: Context) -> AVPlayerViewController {
        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = showsPlaybackControls
        controller.delegate = context.coordinator

        // 添加自定义点击手势
        if let onTap = onTap {
            let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap))
            // 关键设置:不阻止其他控件的触摸事件
            tapGesture.cancelsTouchesInView = false
            controller.view.addGestureRecognizer(tapGesture)
        }

        return controller
    }

    public func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
        uiViewController.player = player
        uiViewController.showsPlaybackControls = showsPlaybackControls
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    public class Coordinator: NSObject, AVPlayerViewControllerDelegate {
        let parent: PlayerViewSUI

        init(parent: PlayerViewSUI) {
            self.parent = parent
        }

        @objc func handleTap() {
            parent.onTap?()
        }
    }
}

使用方式

初始化PlayerViewSUI时直接传入点击回调,无需额外添加SwiftUI手势:

PlayerViewSUI(player: player, onTap: {
    print("Tapped")
})
.frame(maxWidth: .infinity)
.background(Color.black)
.padding(.vertical, 20)
.ignoresSafeArea()
.navigationBarHidden(hideNavigationBar)
.toolbarBackground(.visible, for: .navigationBar)

备选方案:SwiftUI simultaneousGesture(需注意层级)

如果坚持在SwiftUI层面添加手势,可以尝试.simultaneousGesture,但这种方法可能因视图层级问题失效,可靠性不如第一种方案:

PlayerViewSUI(player: player)
.frame(maxWidth: .infinity)
.background(Color.black)
.padding(.vertical, 20)
.ignoresSafeArea()
.navigationBarHidden(hideNavigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.simultaneousGesture(TapGesture().onEnded {
    print("Tapped")
})

内容的提问来源于stack exchange,提问作者Deepak Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 09:07:48