Skip to content

VideoNode Tap to Fullscreen with Smooth Instagram-like Transition #2117

@abbasnaqvi200

Description

@abbasnaqvi200

Hey, could you please help me with code for displaying videos in a table view using ASVideoNode? When the video is tapped, it should transition smoothly to fullscreen, similar to Instagram’s video experience. I’d also like the video to continue playing from where it left off during the transition. Smooth animation is essential for a seamless user experience.

My Video Cell Code is:-

class WallVideoNode: ASCellNode {

let videoNode = ASVideoNode()
let muteButton = ASButtonNode()

var size = CGSize(width:UIScreen.main.bounds.width, height: UIScreen.main.bounds.width)

override init() {
    super.init()
    setupVideoNode()
}

init(size : CGSize) {
    super.init()
    self.size = size
    setupVideoNode()
}

var videoURL : URL?
var mediaFile : MediaFilePath?
var isPlayingOnFullScreen = false


private func setupVideoNode() {
    videoNode.delegate = self
    videoNode.shouldAutorepeat = true
    //videoNode.shouldAutoplay = true
    videoNode.backgroundColor = .black
    videoNode.muted = WallView.currentMuteStatus
    addSubnode(videoNode)
    addSubnode(muteButton)
}

override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
    
    return LayoutSpec {
        videoNode.preferredSize(size).overlay {
            
            InsetLayout(insets: UIEdgeInsets(top: .infinity, left: .infinity, bottom: 10, right: 10)) {
                muteButton.preferredSize(CGSize(width: 30, height: 30))
            }
        }
    }
}

func configureVideo(with mediaFile: MediaFilePath) {
    self.mediaFile = mediaFile
   
    if let url = URL.init(string: mediaFile.wall_Media_Path ?? "") {
        self.videoURL = url
        
        DispatchQueue.global(qos: .background).async {
            let asset = AVAsset(url: url)
            asset.loadValuesAsynchronously(forKeys: ["playable"], completionHandler: {
                DispatchQueue.main.async {
                    asset.cancelLoading()
                    self.videoNode.asset = asset
                }
            })
        }
    }
    
    let placeholder =  mediaFile.gcs_Video_Placeholder ?? ""
    
    self.setWallImage(placeholder, media: mediaFile)

    videoNode.gravity = AVLayerVideoGravity.resizeAspectFill.rawValue // Set Aspect Fill
    muteButton.tintColor = .white
    muteButton.cornerRadius = 15
    videoNode.muted = WallView.currentMuteStatus
    muteButton.isSelected = WallView.currentMuteStatus
    muteButton.backgroundColor = UIColor.black.withAlphaComponent(0.3)
    let size = CGSize(width: 12, height: 12)
    muteButton.setImage(UIImage(named: "ct_unmute_white")?.resize(targetSize:size ), for: .normal)
    muteButton.setImage(UIImage(named: "ct_mute_white")?.resize(targetSize: size), for: .selected)
    muteButton.addTarget(self, action: #selector(muteVideo), forControlEvents: .touchUpInside)
}

func setMuteUnmute() {
    muteButton.isSelected = WallView.currentMuteStatus
    videoNode.muted = WallView.currentMuteStatus
}

@objc func muteVideo() {
    muteButton.isSelected = !muteButton.isSelected
    videoNode.muted = muteButton.isSelected
    WallView.currentMuteStatus = muteButton.isSelected
}

func playVideo() {
    videoNode.play()
}

func pauseVideo() {
    videoNode.pause()
}

}

extension WallVideoNode : ASVideoNodeDelegate {

// ASVideoNodeDelegate method
func didTap(_ videoNode: ASVideoNode) {
    
    if isPlayingOnFullScreen {
        
        self.closestViewController?.presentedViewController?.dismiss(animated: true)
        self.insertSubnode(videoNode, at: 0)
        self.isPlayingOnFullScreen = false
        
    } else {
        isPlayingOnFullScreen = true
        print("Video node tapped!")
        ///videoNode.gravity = AVLayerVideoGravity.resizeAspect.rawValue // Set Aspect Fill
        guard let asset = videoNode.asset else { return }
        //pauseVideo() // Pause the current video and save playback time
        self.transitionToFullScreen()
    }
}

}

extension WallVideoNode {

func transitionToFullScreen() {
    // 1. Get the snapshot of the video node
    guard let vc = self.closestViewController else {return}
    
    
    let heroId = "cell\(1)"
    
    // Setting Hero ID for transition
    let fullScreenSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
    videoNode.frame = CGRect(origin: .zero, size: fullScreenSize)
    videoNode.layoutIfNeeded()
    
    videoNode.view.hero.id = heroId
    
    let detailVC = FullScreenVideoViewController(videoNode: videoNode)
    detailVC.modalPresentationStyle = .overFullScreen
    detailVC.hero.isEnabled = true
    //detailVC.videoNode.view.hero.id = heroId

    detailVC.dismissUpdate = {
        self.insertSubnode(self.videoNode, at: 0)
        self.isPlayingOnFullScreen = false
    }
    
    vc.present(detailVC, animated: false, completion: nil)

}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions