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?
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With