youtube / youtube-ios-player-helper

Lightweight helper library that allows iOS developers to add inline playback of YouTube videos through a WebView
Other
1.65k stars 684 forks source link

Cells containing YTPlayerView leaves its position and overlaps over other uitableview cells on scroll #307

Open adarshroy opened 6 years ago

adarshroy commented 6 years ago

YTPlayerView (Youtube player) is added inside a UITableViewCell. When it is played and minimized (by clicking 'done' or 'minimize' button), when we scroll downwards and that Video-cell is going out of the screen from the bottom edge, it simply doesn't go and tries to stick to the bottom only, while other cells continues to scroll beneath it.

After that when we scroll just reverse we see, the cell is now over other cells overlapping. And if you go more downwards to the actual position of the cell, you will get a 'void' in its actual position.

Inside the Video-cell, the code :

            if let playerHelper = dataSource!["player"] as? YoutubeVideoPlayerHelper 
            {  //'player' key is newly created in this class for the tableArr-dict. This key will store the player for each cell, no-matter if the cell deques or not.
                playerHelper.stopVideo()
            }

            ytHelper = YoutubeVideoPlayerHelper()
            self.dataSource!["player"] = ytHelper
            ytHelper.loadVideo(playerView: self.viewWithTag(VIEW_BASE_TAG+1)!, strVideoUrl: dataSource!["ansAudioURL"] as! String)

           //            ytHelper.loadVideo(playerView: self.viewWithTag(VIEW_BASE_TAG+1)!, strVideoUrl: dataSource!["ansAudioURL"] as! String)
            ytHelper.blockPlayerStateChanged = { (newVideoPlayerState) in  //this is video-player state used in youtube-helper.
                var newState = PlayerState.kStopped //This is audio-player state used in for-you class
                if newVideoPlayerState == YoutubeVideoPlayerHelper.YTState.kEnded {
                    //contentPlayedApi
                    self.callMarkContentPlayedApi()
                }
                else if newVideoPlayerState == YoutubeVideoPlayerHelper.YTState.kPlaying {
                    newState = .kPlaying
                }
                else if newVideoPlayerState == YoutubeVideoPlayerHelper.YTState.kPaused {
                    newState = .kPaused
                }
                (self.dataSource!["ansAudioModel"] as! AudioDataModel).audioPlayingState = newState.rawValue
                self.blockPlayerStateChanged!(newState)
            }
            //--youtube
            let audioModelObj = dataSource!["ansAudioModel"] as! AudioDataModel
            let currPlayingState = PlayerState(rawValue: audioModelObj.audioPlayingState!)!
            if currPlayingState == .kStopped {
                ytHelper.stopVideo()
            }

YoutubeVideoPlayerHelper class:

import UIKit
import youtube_ios_player_helper

class YoutubeVideoPlayerHelper: NSObject {

    enum YTState {
        case  kUnStarted, kPlaying, kPaused, kEnded
    }

    var ytVideoPlayerView: YTPlayerView!
    var blockPlayerStateChanged:((YTState)->())? = nil

    func loadVideo(playerView: UIView,strVideoUrl: String) {
        ytVideoPlayerView = playerView as! YTPlayerView
        ytVideoPlayerView.delegate = self
        let playerVars = [
            "controls": 1,
            "playsinline" : 0,
            //            "autoplay" : 1,
            //            "autohide" : 1,
            "rel" : 0,
            "showinfo" : 0,
            //            "modestbranding" : 1
        ]

        if let videoID = self.extractYoutubeIdFromLink(link: strVideoUrl) {
            let result = ytVideoPlayerView.load(withVideoId: videoID, playerVars: playerVars) //S094ZseEnEQ, 0gosur3db5I
            debugPrint(result)
        }
    }

    func stopVideo() {
        if ytVideoPlayerView != nil {
            ytVideoPlayerView.stopVideo()
        }
    }

    func playVideo() {
        if ytVideoPlayerView != nil {
            ytVideoPlayerView.playVideo()
        }
    }

    func pauseVideo() {
        if ytVideoPlayerView != nil {
            ytVideoPlayerView.pauseVideo()
        }
    }

    fileprivate func extractYoutubeIdFromLink(link: String) -> String? {
        let pattern = "((?<=(v  |V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
        guard let regExp = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) else {
            return nil
        }
        let nsLink = link as NSString
        let options = NSRegularExpression.MatchingOptions(rawValue: 0)
        let range = NSRange(location: 0, length: nsLink.length)
        let matches = regExp.matches(in: link as String, options:options, range:range)
        if let firstMatch = matches.first {
            return nsLink.substring(with: firstMatch.range)
        }
        return nil
    }

}

extension YoutubeVideoPlayerHelper: YTPlayerViewDelegate {
    func playerView(_ playerView: YTPlayerView, didChangeTo state: YTPlayerState) {
        var ytState: YTState = .kUnStarted
        switch (state) {
        case YTPlayerState.playing:
            debugPrint("Started playback")
            ytState = .kPlaying
            break
        case YTPlayerState.paused:
            debugPrint("Paused playback")
            ytState = .kPaused
            break
        case YTPlayerState.ended:
            debugPrint("ended playback")
            ytState = .kEnded
            break
        case YTPlayerState.buffering:
            debugPrint("ended buffering")
            ytState = .kPlaying
            break
        default:
            break
        }
        blockPlayerStateChanged?(ytState)
    }

    func playerViewDidBecomeReady(_ playerView: YTPlayerView) {
        debugPrint("1")
    }

    func playerView(_ playerView: YTPlayerView, didPlayTime playTime: Float) {
        debugPrint(playTime)
    }
}

Actual Position of the video cell :

simulator screen shot 18-apr-2018 4 45 00 pm

---------------------------------------------------------------------------

Now the VOID created at its actual position when the video cell left its place:

simulator screen shot 18-apr-2018 4 42 15 pm

---------------------------------------------------------------------------

The current position of the video cell when it jumped over other cells and overlapped over them:

simulator screen shot 18-apr-2018 4 41 43 pm

nick1ee commented 6 years ago

Hi @adarshroy

I got into the same trouble these days.. After doing some tests, I got a pattern to solve this problem. Not sure it is the best solution or not, just share my opinion with you.

You should stopPlayingVideo in endDisplayingCell function and when system is going to reuse the cell, you should remove the previous playerView and create a new one, then setup the video Id.

Please let me know if this pattern helped you to solve this problem or any other suggestion on this problem.

Thanks!