简体   繁体   English

如何从自定义视图过渡到AVPlayerViewController?

[英]How to transition to AVPlayerViewController from a custom view?

I have a custom view: 我有一个自定义视图:

class MediaPlayerView: UIView {

    var mediaURL: URL? {
        didSet {
            determineMediaType()
        }
    }
    let videoExtensions = ["mov"]

    override init (frame : CGRect) {
        super.init(frame : frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func determineMediaType() {
        let url = self.mediaURL
        let pathExtention = url?.pathExtension
        if videoExtensions.contains(pathExtention!) {
            print("Movie URL: \(String(describing: url))")
            setupVideo(url: url!)
        } else {
            print("Image URL: \(String(describing: url))")
            setupImage(url: url!)
        }
    }

    func setupVideo(url: URL) {
        let playButton = UIImage(named: "Play Triangle")
        let playButtonView = UIImageView(image: playButton!)
        let singleTap = UITapGestureRecognizer(target: self,  action: #selector(tapDetected))
        playButtonView.addGestureRecognizer(singleTap)
        playButtonView.center = self.center
        playButtonView.frame.size.width  = self.frame.size.width/5
        playButtonView.frame.size.height = self.frame.size.height/5
        playButtonView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
        playButtonView.isUserInteractionEnabled = true
        self.addSubview(playButtonView)
    }

    @objc func tapDetected() {
        print("tap!")

        let player = AVPlayer(url: self.mediaURL!)
        let controller = AVPlayerViewController()
        controller.player = player
        self.window?.rootViewController?.present(controller, animated: true) {
            player.play()
        }
    }

    func setupImage(url: URL) {
        let imageView = UIImageView()
        imageView.frame = self.bounds
        imageView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
        self.addSubview(imageView)
        imageView.kf.setImage(with: url)
    }

}

However when I click the play button, I get the following error: 但是,当我单击播放按钮时,出现以下错误:

Warning: Attempt to present <AVPlayerViewController: 0x7fe8b200b000> on <SweatNet.MainTabBarController: 0x7fe8b4816400> whose view is not in the window hierarchy!

It comes on this line: self.window?.rootViewController?.present. 它位于以下行:self.window?.rootViewController?.present。 I think It is getting confused by me calling the rootViewController (which seems to be SweatNet.MainTabBarController). 我认为调用rootViewController(似乎是SweatNet.MainTabBarController)使我感到困惑。 I want to it to call SweatNet.TagViewController. 我要它调用SweatNet.TagViewController。 This is the one which contains the cell which contains the custom MediaPlayerView, but I don't understand how to get a reference to this. 这是一个包含包含自定义MediaPlayerView的单元格的单元格,但是我不知道如何获得对此的引用。

Try this: 尝试这个:

class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
    if let navigationController = controller as? UINavigationController {
        return topViewController(controller: navigationController.visibleViewController)
    }
    if let tabController = controller as? UITabBarController {
        if let selected = tabController.selectedViewController {
            return topViewController(controller: selected)
        }
    }
    if let presented = controller?.presentedViewController {
        return topViewController(controller: presented)
    }
    return controller
}

Write your method as: 将您的方法编写为:

@objc func tapDetected() {
    print("tap!")

    let player = AVPlayer(url: self.mediaURL!)
    let controller = AVPlayerViewController()
    controller.player = player
    topViewController().present(controller, animated: true) {
        player.play()
    }
}

This will return you top vc in hierarchy. 这将返回您在层次结构中排名靠前的vc。 Hope it helps! 希望能帮助到你!

I would be interested in some feedback on this answer as I think its an example of me thinking about the iOS system the wrong way. 我会对对此答案的一些反馈感兴趣,因为我认为这是我以错误的方式思考iOS系统的一个例子。 What I eventually realized was that I was trying to put view controller code inside of a custom view. 我最终意识到,我试图将视图控制器代码放入自定义视图中。 View controller code being the code to launch the AVPlayerViewController. 查看控制器代码是启动AVPlayerViewController的代码。 Rather I should put this logic in my view controller. 相反,我应该将此逻辑放在我的视图控制器中。

What I did which works is use the collectionView delegate method didSelectItemAt indexPath: IndexPath inside of the view controller where the view controller logic for the collection view is held like so: 我所做的工作是在视图控制器内部使用collectionView委托方法didSelectItemAt indexPath:IndexPath,其中保存了集合视图的视图控制器逻辑,如下所示:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if collectionView == self.collectionView {
        let post = posts[indexPath.row]
        if post.isVideo == true {
            self.performSegue(withIdentifier: "playVideo", sender: nil)
        } else {
            print("is image. might go full screen one day here")
        }
}

This works and I believe it is better than writing a custom aspect of the view to launch the AVPlayerViewController. 这行得通,我认为这比编写视图的自定义方面启动AVPlayerViewController更好。 But it also could be that both approaches work - I really don't know enough about iOS development to make that call. 但也有可能两种方法都起作用-我真的对iOS开发了解得还不够多,所以无法打电话。 Any comments are welcome. 欢迎任何意见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM