Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 975
user86516512 Avatar asked May 13 '21 17:05

user86516512


People also ask

How do I load a view view controller?

Add views to your view controller To that root view, you add the custom views you need to present your interface. In storyboards, you add views by dragging them onto the view controller scene. For example, the following figure shows a view controller with an image view and button on an iPhone.

What is the difference between View and Controller?

The view renders presentation of the model in a particular format. The controller responds to the user input and performs interactions on the data model objects. The controller receives the input, optionally validates it and then passes the input to the model.


Video Answer


1 Answers

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.

like image 104
iUrii Avatar answered Oct 21 '22 09:10

iUrii