SwiftUI封装AVPlayerView最佳实践及修剪交互失效问题排查
解决SwiftUI封装AVPlayerView修剪功能双击崩溃及交互失效问题
问题分析
你遇到的-[AVTrimIndicatorAccessibilityElement accessibilityHitTest:]: unrecognized selector崩溃,是因为AVPlayerView内部的私有辅助功能元素AVTrimIndicatorAccessibilityElement未实现accessibilityHitTest:方法,在SwiftUI的NSViewRepresentable封装场景下,辅助功能事件被错误传递给该元素,导致崩溃并丢失交互。机型差异是由于不同macOS版本中AVPlayerView的内部辅助元素实现不一致。
解决方案
1. 自定义容器NSView拦截辅助功能事件
创建一个包裹AVPlayerView的自定义NSView子类,重写accessibilityHitTest:方法,避免事件传递给内部有问题的辅助元素:
import AVKit import AppKit class CustomPlayerContainerView: NSView { let playerView = AVPlayerView() override init(frame frameRect: NSRect) { super.init(frame: frameRect) setupPlayerView() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupPlayerView() { addSubview(playerView) playerView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ playerView.topAnchor.constraint(equalTo: topAnchor), playerView.leadingAnchor.constraint(equalTo: leadingAnchor), playerView.trailingAnchor.constraint(equalTo: trailingAnchor), playerView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) // 开启修剪功能 playerView.canTrim = true } override func accessibilityHitTest(_ point: NSPoint) -> NSAccessibilityElement? { // 拦截事件,返回自身或nil,避免传递给内部的AVTrimIndicatorAccessibilityElement let convertedPoint = convert(point, to: playerView) guard playerView.hitTest(convertedPoint) != nil else { return nil } return self } // 可选:隐藏内部辅助元素,进一步避免冲突 override var accessibilityChildren: [Any]? { return [] } }
2. 修改NSViewRepresentable使用自定义容器
将原来直接封装AVPlayerView的代码,改为使用上面的自定义容器:
import SwiftUI import AVKit struct AVPlayerTrimView: NSViewRepresentable { let player: AVPlayer func makeNSView(context: Context) -> CustomPlayerContainerView { let container = CustomPlayerContainerView() container.playerView.player = player return container } func updateNSView(_ nsView: CustomPlayerContainerView, context: Context) { if nsView.playerView.player != player { nsView.playerView.player = player } } } // 使用示例 struct ContentView: View { let player = AVPlayer(url: URL(fileURLWithPath: "/path/to/your/video.mp4")) var body: some View { AVPlayerTrimView(player: player) .frame(height: 400) } }
验证效果
在出现问题的Mac机型上测试,双击修剪区域应该不会再触发崩溃,修剪控件的交互性也会恢复正常。
内容的提问来源于stack exchange,提问作者Chocoford
相关产品推荐
相关产品推荐

