Решение, которое также работает с наследуемыми классами:
from itertools import chain
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Mixin(object):
def as_dict(self):
tables = [base.__table__ for base in self.__class__.__bases__ if base not in [Base, Mixin]]
tables.append(self.__table__)
return {c.name: getattr(self, c.name) for c in chain.from_iterable([x.columns for x in tables])}
Спасибо за ваши ответы. Я решаю это следующим образом:
Вместо того, чтобы отображать Player на настройке в ячейке, теперь добавляю эскиз в ячейку и кнопку на миниатюре, чтобы каждый раз, когда пользователь нажимает кнопку воспроизведения, он открывается новый контроллер (ранее я представлял в UIWindow
) и представлял его как modalPresentationStyle
из overFullScreen
, используя протокол, потому что ячейка не может представлять ViewController.
Протокол: (в классе YouTubePlayerCell)
protocol PresentControllerDelegate: class {
func loadNewScreen(controller: UIViewController) -> Void
}
Финал YouTubePlayer.swift
:
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)
}
}
}
Реализация делегата в CollectionViewController:
extension ChatViewController: PresentControllerDelegate {
func loadNewScreen(controller: UIViewController) {
self.present(controller, animated: true, completion: nil)
}
}
Конечный исходный код можно найти здесь: https : //github.com/fossasia/susi_iOS/pull/372
Почему вы добавляете плеер в качестве подвидного при каждом воспроизведении видео? Мое предложение было бы, поскольку вы добавляете представление игрока на весь экран, вы можете иметь только один экземпляр представления и добавить его только один раз (может быть в начале) и сохранить его скрытым. Для воспроизведения видео просто покажите плеер и загрузите видео.
Вместо этого лучше всего будет иметь контроллер View для Youtube Player и представить его с идентификатором видео каждый раз, когда вам нужно играть, а затем увольнять, когда это делается.
Я вижу, что в приведенном ниже коде
if let videoId = message.videoData?.identifier {
cell.loadVideo(with: videoId)
}
вы вызываете метод loadVideo, который отвечает за показ проигрывателя. Поэтому при прокрутке вы повторно используете ячейку, и она вызывает метод loadVideo и представляет игрока. поэтому решение не запускает воспроизведение видео по умолчанию при отображении ячейки, предоставляет кнопку воспроизведения / паузы на оверлете сотового видео и при нажатии кнопки начинает воспроизведение видео. Если мой анализ неправильный, сообщите мне, какая именно проблема у вас есть.