user86516512
user86516512

Reputation: 445

Tapping on a video in a table view cell to open it in a view controller

tl;dr I'm trying to recreate this in the Twitter app: https://i.imgur.com/173CVyM.mp4

As you can see, Twitter plays a video in the feed (table view cell) and when the video is tapped, the video smoothly transitions into its own view controller, without stopping or buffering the video.

I have the video playing in the feed part done (in the table view cell), but now I'm stuck on how to actually smoothly transition the video into a view controller on tap.

At a high level, what do I need to do here?

My current setup has an AVPlayer instance as part of each table view cell. Would I pass the AVPlayer instance to the view controller and continue playing the video from there? What about memory management? I feel like having one AVPlayer instance for each table view cell is going to cause some issues, but I'm not entirely sure.

As a secondary question, if I wanted to ignore the fancy animation/transition, how could I continue playing the video seamlessly in a view controller when it's tapped in the table view cell?

Upvotes: 12

Views: 552

Answers (1)

iUrii
iUrii

Reputation: 13788

To make the transition from your video cell to the player controller you can use your AVPlayerLayer and a custom animation, e.g:

ViewController.swift

// Present player controller
let playerViewController = AVPlayerViewController()
playerViewController.player = player // Your current player instance
playerViewController.transitioningDelegate = self // Custom animation
        
self.present(playerViewController, animated: true, completion: nil)
extension ViewController: UIViewControllerTransitioningDelegate {
  func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return PlayerAnimationController(playerLayer: playerLayer) // Your current player's layer
  }
}

PlayerAnimationController.swift

class PlayerAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
    
    let playerLayer: AVPlayerLayer
    
    init(playerLayer: AVPlayerLayer) {
        self.playerLayer = playerLayer
    }
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.5
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toView = transitionContext.view(forKey: .to) else { return }
        
        let containerView = transitionContext.containerView
        containerView.addSubview(toView)
        
        let originalSuperlayer = playerLayer.superlayer
        let originalFrame = playerLayer.frame
        
        let frame = playerLayer.convert(playerLayer.bounds, to: nil)
        containerView.layer.addSublayer(self.playerLayer)
        
        // Start frame
        CATransaction.begin()
        CATransaction.setAnimationDuration(0)
        CATransaction.setDisableActions(true)
        
        self.playerLayer.frame = frame
        
        CATransaction.commit()
        
        toView.alpha = 0
        
        DispatchQueue.main.async {
            let duration = self.transitionDuration(using: transitionContext)
            UIView.animateKeyframes(withDuration: duration, delay: 0) {
                UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1/2) {
                    self.playerLayer.frame = containerView.bounds
                }
                
                UIView.addKeyframe(withRelativeStartTime: 1/2, relativeDuration: 1/2) {
                    toView.alpha = 1.0
                }
            }
            completion: { _ in
                originalSuperlayer?.addSublayer(self.playerLayer)
                self.playerLayer.frame = originalFrame
                
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
            }
        }
    }   
}

The sample uses AVPlayerViewController but you can use your own one of course.

Upvotes: 3

Related Questions