web-dev-qa-db-ja.com

AVPlayerViewControllerでのボタンクリックイベントの完了

AVPlayerViewControllerでローカルビデオを再生したいのですが、[完了]ボタンのクリックイベントが見つかりませんでした。

私のビデオはAVPlayerViewControllerで再生できますが、次のボタン、前のボタン、完了したボタンのクリックイベントが見つかりませんでした。

15
Yogendra Patel

公式には、完了ボタンのクリックイベントはありません。Appleからのエンジニアがそれについて述べました here )。

私の調査に関しては、完了ボタンがクリックされた場合にイベントを取得するための、しかし間接的な方法が1つあることを知りました。

完了ボタンをクリックすると変化するAVPlayerViewControllerの唯一の変数はAVPlayerViewController.view.frameであることがわかりました。まず最初に、view.frameがviewControllerの中央に表示されます。

animated : trueで表示すると、viewControllerの下部に移動し、中央に戻ります。クリックすると下に戻ります。

animated : falseで表示すると、2つの変更のみが行われます。フレームは、ビデオの再生を開始するとviewControllerの中央になり、下部では[完了]をクリックすると表示されます。

したがって、present(PlayerViewController, animated : true)へのコールバックのAVPlayerViewController.view.frameにオブザーバーを追加すると、完了ボタンをクリックしたときにオブザーバーが1回だけ呼び出され、ビデオビューが画面外になります。

私の場合、AVPlayerViewControllerにモーダルでアニメーションが表示されました。以下のコードは私のために働きました:

Swift 3.0

override func viewDidLoad()
{
    super.viewDidLoad()

    let videoURL = NSURL(fileURLWithPath:Bundle.main.path(forResource: "MyVideo", ofType:"mp4")!)
    let player = AVPlayer(url: videoURL as URL)

    present(playerViewController, animated: false) { () -> Void in
        player.play()

        self.playerViewController.player = player
        self.playerViewController.addObserver(self, forKeyPath: #keyPath(UIViewController.view.frame), options: [.old, .new], context: nil)
    }}
    override func observeValue(forKeyPath keyPath: String?,
                           of object: Any?,
                           change: [NSKeyValueChangeKey : Any]?,
                           context: UnsafeMutableRawPointer?)
{

    print(self.playerViewController.view.frame)
    //Player view is out of the screen and
    //You can do your custom actions
}

また、[完了]をクリックすると、AVPlayerViewControllerが閉じられず、ParentViewController.presentedViewControllerに表示されるため、このプロパティにオブザーバーを追加できないことがわかりました

15
vmchar


これは、DoneからAVPlayerViewControllerボタンクリックイベントを取得するために行いました。

まず、以下のようにNotification.Nameの拡張機能を作成します

extension Notification.Name {
static let kAVPlayerViewControllerDismissingNotification = Notification.Name.init("dismissing")
}

次に、AVPlayerViewControllerの拡張を作成し、次のようにviewWillDisappearをオーバーライドします。

// create an extension of AVPlayerViewController
extension AVPlayerViewController {
    // override 'viewWillDisappear'
    open override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // now, check that this ViewController is dismissing
        if self.isBeingDismissed == false {
            return
        }

        // and then , post a simple notification and observe & handle it, where & when you need to.....
        NotificationCenter.default.post(name: .kAVPlayerViewControllerDismissingNotification, object: nil)
    }
}

これはISボタンのイベントを処理するための基本的な機能のみです。

ハッピーコーディング...

13
Vatsal Shukla

これは、@ vmcharによる回答からの小さな改善です。

.isBeingDismissedメソッドを使用して、フレームを分析する代わりに、AVPlayerViewControllerが閉じられていることを確認できます。

...

let videoURL = NSURL(fileURLWithPath:"video.mp4")
let player = AVPlayer(url: videoURL as URL)

present(playerViewController!, animated: false) { () -> Void in
    player.play()

    self.playerViewController!.player = player
    self.playerViewController!.addObserver(self, forKeyPath:#keyPath(UIViewController.view.frame), options: [.old, .new], context: nil)
...

次に、値を観察する

override func observeValue(forKeyPath keyPath: String?,
                           of object: Any?,
                           change: [NSKeyValueChangeKey : Any]?,
                           context: UnsafeMutableRawPointer?)
{

    if (playerViewController!.isBeingDismissed) {  
     // Video was dismissed -> apply logic here
    } 
} 
2
Dipo Areoye

私にとって最も簡単な解決策は、AVPlayerViewControllerをサブクラス化し、それに単純な完了ブロックを追加することでした。

class MYVideoController: AVPlayerViewController {

  typealias DissmissBlock = () -> Void
  var onDismiss: DissmissBlock?

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if isBeingDismissed {
      onDismiss?()
    }
  }
}

使用法

...
let avPlayerViewController = MYVideoController()
avPlayerViewController.onDismiss = { [weak self] in 
    print("dismiss")
}
1
inokey

猫の皮をむく方法はたくさんあると思います。 「完了」クリックイベントを処理する必要がありました。私の場合、「X」がクリックされ、AVPlayerViewControllerが完全に閉じられた(閉じられた)後、イベントにフックできることを確認したかったのです。

Swift 4.0

protocol TableViewCellVideoPlayerViewControllerDelegate: class {
    func viewControllerDismissed()
}

class MyPlayerViewController: AVPlayerViewController {

    weak var navDelegate: TableViewCellVideoPlayerViewControllerDelegate?

    open override func viewDidDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if self.isBeingDismissed {
            self.navDelegate?.viewControllerDismissed()
        }
    }
}

class TodayCell: UITableViewCell, SFSafariViewControllerDelegate,  TableViewCellVideoPlayerViewControllerDelegate {
    func viewControllerDismissed() {
        self.continueJourney()
    }
 }
0
Clay Martin

私はAVPlayerViewControllerをサブクラス化する必要がない回避策を見つけました。これは、ドキュメントに明確にすべきではないと記載されています( https://developer.Apple.com/documentation/avkit/avplayerviewcontroller )。それはきれいではありませんが、AVPlayerViewControllerが却下されたときにコードを実行する場所を私に与えることで、仕事は完了しました。

AnyViewController: UIViewController, AVPlayerViewControllerDelegate {
    private let playerVC = AVPlayerViewController()

    override func viewDidLoad() {
        playerVC.delegate = self        
    }

    func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        if playerViewController.isBeingDismissed {
            playerViewController.dismiss(animated: false) { [weak self] in
                self?.someDismissFunc()
            }
        }
    }
}

私が言うことができる限り、これを行うきれいな方法がないのは本当にめちゃくちゃです:(

0
kentrh

私は同じ問題を抱えていて、別のトリックを見つけました(YoutubePlayer Swiftフレームワークで動作しますが、他の用途に適応させることができるかもしれません)。

私の場合、Doneボタンを押し、フルスクリーンビデオプレーヤーのPauseボタンを押すと、どちらもYoutubePlayerでpauseイベントが発生します。ただし、ビデオが別のウィンドウで再生されるので、アプリケーションのメインウィンドウをサブクラス化し、becomeKey関数とresignKey関数をオーバーライドして、ウィンドウがキーウィンドウかどうかを保存しました。

class MyWindow:UIWindow {
    override func becomeKey() {
        Services.appData.myWindowIsKey = true
    }

    override func resignKey() {
        Services.appData.myWindowIsKey = false
    }
}

それができたら、ビデオの状態が一時停止になったときにウィンドウがキーであるかどうかを確認できます。Doneボタンを押すと、ウィンドウisキーウィンドウであり、閉じることができます私のビデオビューコントローラー、およびPauseの場合、私のウィンドウis notキーウィンドウなので、何もしません。

0
TheEye