SwiftUI父视图的onTapGesture拦截了来自嵌入的AVPlayerViewController的点击事件

移动开发 2026-07-08

我在一个包含父级 .onTapGesture 的SwiftUI视图层次结构中,通过 UIViewControllerRepresentable 嵌入一个 AVPlayerViewController

在某些较旧的iOS版本中,点击视频播放器也会被父级SwiftUI手势识别。在下面的示例中,当我点击视频播放器时,会打印出“hello”。AVPlayerViewController 控件(播放/暂停、进度条等)会正确地出现和隐藏,但控件本身有时对点击没有响应。

看起来父级SwiftUI手势识别器正在与嵌入的UIKit控制器所接收的触摸发生竞争或拦截。 在iOS 26上测试,效果如预期。请问谁能帮我解决在点击视频播放器时不打印“hello”,并让控件能够正确响应点击的问题吗?

先行感谢!

struct VideoPlayer: UIViewControllerRepresentable {
    typealias UIViewControllerType = AVPlayerViewController

    private let player: AVPlayer?

    init(player: AVPlayer?) {
        self.player = player
        player?.allowsExternalPlayback = false
    }

    func makeUIViewController(context: Context) -> AVPlayerViewController {
        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = true
        return controller
    }

    func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {}

}

struct VideoPlayerView: View {

    @State
    private var player: AVPlayer?

    let data: Data
    let design: Design

    init(player: AVPlayer? = nil, data: Data, design: Design) {
        self.player = URL(string: data.videoUrl).map(AVPlayer.init(url:))
        self.data = data
        self.design = design
    }

    var body: some View {
        inlinePlayer
        .frame(height: design.playerFixedHeight)
        .clipShape(RoundedRectangle(cornerRadius: 5))
        .contentShape(RoundedRectangle(cornerRadius: 5))
    }

    private var inlinePlayer: some View {
       VideoPlayer(player: player)
    }

}

extension VideoPlayerView {
    struct Data {
        let videoUrl: String
     }
}

extension VideoPlayerView {
    struct Design {
        let playerFixedHeight: CGFloat = 300
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello, world!")
                .background(Color.blue.frame(height: 100))

            VideoPlayerView(data: .init(videoUrl: "https://www.pexels.com/download/video/5340598/"), design: .init())

        }
        .padding()
        .onTapGesture {
            print("hello")
        }
    }
}

解决方案

在你提到的问题中:

Tested on iOS 26 works as it should.

当我在iPhone 17模拟器上使用iOS 26.5测试时,点击手势只有在点击带蓝色背景的文本时才会触发。所以如果这是你希望它工作的方式,那么可能的变通方案有:

1.将点击手势附加到 Text 上,而不是附加到 VStack

手势应在蓝色背景之后应用,这样也会作用于背景:

VStack {
    Text("Hello, world!")
        .background(Color.blue.frame(height: 100))
        .onTapGesture { // 👈 moved to here
            print("hello")
        }

    VideoPlayerView(data: .init(videoUrl: "https://www.pexels.com/download/video/5340598/"), design: .init())

}
.padding()

2.给 VStack 添加背景,并将点击手势附着在此上

采用这种方法,你需要把 .allowsHitTesting(false) 应用于 Text(蓝色背景之后),以允许手势透传。

也可以把 Color.clear 作为 VStack 背后的背景——如果这样做,请应用一个内容形状使其对点击有响应:

VStack {
    Text("Hello, world!")
        .background(Color.blue.frame(height: 100))
        .allowsHitTesting(false) // 👈 added

    VideoPlayerView(data: .init(videoUrl: "https://www.pexels.com/download/video/5340598/"), design: .init())

}
.padding()
.background { // 👈 added
    Color.clear
        .contentShape(.rect)
        .onTapGesture { // 👈 moved to here
            print("hello")
        }
}

以这种方式应用点击手势时,蓝色矩形左侧和右侧的空白区域也会对点击做出响应。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章