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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:57:35