在滚动CollectionView期间不必要地打开了YouTube播放器

时间:2018-07-13 05:04:54

标签: ios swift uicollectionview uicollectionviewcell youtubeplayer

我正在使用一个聊天机器人,其中来自服务器的响应类型不同,并且我在聊天屏幕中使用// Client if conn, err := net.Dial("tcp", addr); err == nil { _, err := conn.Write([]byte("hello")) if err != nil { fmt.Println(err) conn.Close() return } else { fmt.Println("ok") } // sleep 10 seconds and re-send time.Sleep(10*time.Second) b := make([]byte, 400000) for i := range b { b[i] = 'x' } n, err := conn.Write(b) if err != nil { fmt.Println(err) conn.Close() return } else { fmt.Println("ok", n) } // sleep 10 seconds and re-send time.Sleep(10*time.Second) } else { panic(err) } 单元格显示了响应。根据服务器响应,会出现不同类型的单元。当服务器响应播放视频时,我正在显示包含youtube播放器的单元。我正在使用https://github.com/kieuquangloc147/YouTubePlayer-Swift。问题是,当我滚动聊天屏幕(collectionView)youtube播放器一次又一次打开时。有时,它阻止了所有UI元素并停止滚动。我尝试了其他方法,但无法解决。这是代码: UICollectionView

PlayerView

import UIKit class PlayerView: UIView, YouTubePlayerDelegate { override init(frame: CGRect) { super.init(frame: frame) addYotubePlayer() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // youtube player lazy var youtubePlayer: YouTubePlayerView = { let viewFrame = UIScreen.main.bounds let player = YouTubePlayerView(frame: CGRect(x: 0, y: 0, width: viewFrame.width - 16, height: viewFrame.height * 1/3)) player.delegate = self return player }() // used as an overlay to dismiss the youtube player let blackView = UIView() // youtube player loader lazy var playerIndicator: UIActivityIndicatorView = { let indicator = UIActivityIndicatorView() indicator.activityIndicatorViewStyle = .whiteLarge indicator.hidesWhenStopped = true return indicator }() // shows youtube player func addYotubePlayer() { if let window = UIApplication.shared.keyWindow { blackView.frame = window.frame self.addSubview(blackView) blackView.backgroundColor = UIColor(white: 0, alpha: 0.5) let tap = UITapGestureRecognizer(target: self, action: #selector(handleDismiss)) tap.numberOfTapsRequired = 1 tap.cancelsTouchesInView = false blackView.addGestureRecognizer(tap) let centerX = UIScreen.main.bounds.size.width / 2 let centerY = UIScreen.main.bounds.size.height / 2 blackView.addSubview(playerIndicator) playerIndicator.center = CGPoint(x: centerX, y: centerY) playerIndicator.startAnimating() blackView.addSubview(youtubePlayer) youtubePlayer.center = CGPoint(x: centerX, y: centerY) blackView.alpha = 0 youtubePlayer.alpha = 0 UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { self.blackView.alpha = 1 self.youtubePlayer.alpha = 1 }, completion: nil) } } func play(_ videoID: String) { youtubePlayer.loadVideoID(videoID) } @objc func handleDismiss() { blackView.removeFromSuperview() UIApplication.shared.keyWindow?.viewWithTag(24)?.removeFromSuperview() UIApplication.shared.keyWindow?.removeFromSuperview() } func playerReady(_ videoPlayer: YouTubePlayerView) { self.playerIndicator.stopAnimating() } func playerStateChanged(_ videoPlayer: YouTubePlayerView, playerState: YouTubePlayerState) { } func playerQualityChanged(_ videoPlayer: YouTubePlayerView, playbackQuality: YouTubePlaybackQuality) { } } (我在YouTubePlayerCell中出现,当服务器响应视频时):

collectionView

这是我在import UIKit class YouTubePlayerCell: ChatMessageCell { var player: PlayerView = PlayerView(frame: UIScreen.main.bounds) override func setupViews() { super.setupViews() setupCell() } func setupCell() { messageTextView.frame = CGRect.zero textBubbleView.frame = CGRect.zero } func loadVideo(with videoID: String) { player.tag = 24 UIApplication.shared.keyWindow?.addSubview(player) player.play(videoID) } override func prepareForReuse() { super.prepareForReuse() player.removeFromSuperview() UIApplication.shared.keyWindow?.viewWithTag(24)?.removeFromSuperview() } } 的{​​{1}}方法中展示YouTubePlayerCell的方式

cellForItemAt

完整的源代码可以在这里找到:https://github.com/imjog/susi_iOS/tree/ytplayer

3 个答案:

答案 0 :(得分:1)

我可以在下面的代码中看到

if let videoId = message.videoData?.identifier {
                        cell.loadVideo(with: videoId)
                    }

您正在调用 loadVideo 方法,该方法负责显示播放器。 因此,在滚动时,您将重复使用该单元格,它会调用 loadVideo 方法并显示播放器。因此解决方案是默认情况下,在显示单元格时不开始播放视频,在单元格视频叠加层上提供播放/暂停按钮,然后单击该按钮即可开始播放视频。 如果我的分析是错误的,请告诉我您遇到的确切问题。

答案 1 :(得分:0)

为什么每次必须播放视频时都将播放器添加为子视图?我的建议是,当您在整个屏幕上添加播放器视图时,您可以只拥有一个视图实例并仅添加一次(可能在开始时)并将其隐藏。要播放视频,只需取消隐藏播放器并加载视频即可。

相反,最佳做法是为Youtube Player配备一个View控制器,并在每次播放时将其与视频ID一起显示,然后在完成播放后将其关闭。

答案 2 :(得分:0)

感谢您的回答。我可以这样解决:

我现在不向播放器介绍该单元格上的设置,而是向该单元格中添加一个缩略图,并在缩略图视图上添加一个按钮,以便每当用户单击 play 按钮时,它都会打开一个新控制器以前,我是在UIWindow中进行演示的,并通过使用协议将其展示为modalPresentationStyle的{​​{1}}的原因,因为单元格无法展示ViewController。

协议 :(在YouTubePlayerCell类中)

overFullScreen

最终protocol PresentControllerDelegate: class { func loadNewScreen(controller: UIViewController) -> Void }

YouTubePlayer.swift

CollectionViewController 中委托实现:

import UIKit
import Kingfisher

protocol PresentControllerDelegate: class {
    func loadNewScreen(controller: UIViewController) -> Void
}

class YouTubePlayerCell: ChatMessageCell {

    weak var delegate: PresentControllerDelegate?

    var message: Message? {
        didSet {
            addThumbnail()
        }
    }

    lazy var thumbnailView: UIImageView = {
        let imageView = UIImageView()
        imageView.image = ControllerConstants.Images.placeholder
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.layer.cornerRadius = 15
        imageView.isUserInteractionEnabled = true
        return imageView
    }()

    lazy var playButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(ControllerConstants.Images.youtubePlayButton, for: .normal)
        button.addTarget(self, action: #selector(playVideo), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    override func setupViews() {
        super.setupViews()
        setupCell()
        prepareForReuse()
    }

    func setupCell() {
        messageTextView.frame = CGRect.zero
        textBubbleView.frame = CGRect(x: 8, y: 0, width: 208, height: 158)
        textBubbleView.layer.borderWidth = 0.2
        textBubbleView.backgroundColor = .white
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        thumbnailView.image = nil
    }

    func addThumbnail() {
        textBubbleView.addSubview(thumbnailView)
        textBubbleView.addConstraintsWithFormat(format: "H:|-4-[v0]-4-|", views: thumbnailView)
        textBubbleView.addConstraintsWithFormat(format: "V:|-4-[v0]-4-|", views: thumbnailView)
        self.downloadThumbnail()
        self.addPlayButton()
    }

    func addPlayButton() {
        thumbnailView.addSubview(playButton)
        playButton.heightAnchor.constraint(equalToConstant: 44).isActive = true
        playButton.widthAnchor.constraint(equalToConstant: 44).isActive = true
        playButton.centerXAnchor.constraint(equalTo: thumbnailView.centerXAnchor).isActive = true
        playButton.centerYAnchor.constraint(equalTo: thumbnailView.centerYAnchor).isActive = true
    }

    func downloadThumbnail() {
        if let videoID = message?.videoData?.identifier {
            let thumbnailURLString = "https://img.youtube.com/vi/\(videoID)/default.jpg"
            let thumbnailURL = URL(string: thumbnailURLString)
            thumbnailView.kf.setImage(with: thumbnailURL, placeholder: ControllerConstants.Images.placeholder, options: nil, progressBlock: nil, completionHandler: nil)
        }
    }

    @objc func playVideo() {
        if let videoID = message?.videoData?.identifier {
            let playerVC = PlayerViewController(videoID: videoID)
            playerVC.modalPresentationStyle = .overFullScreen
            delegate?.loadNewScreen(controller: playerVC)
        }
    }

}

最终源代码可以在这里找到:https://github.com/fossasia/susi_iOS/pull/372