AVPlayer внутри UITableViewCell с автоматической компоновкой других видов - PullRequest
4 голосов
/ 18 января 2020

У меня есть UITableViewCell с UILabel и AVPlayer, который воспроизводит видео из онлайн, которое мне нужно реализовать. Проблема в том, что AVPlayer, который Apple дает , не может использовать автоматическую разметку для правильного отображения видео.

Я полагаю, что существуют способы реализации UIView для смешанного ограничения и разметки кадра. Я думаю, что есть еще кое-что в этом вопросе: кажется, есть проблема с тем фактом, что видео не загружается при инициализации.

UITableViewCell

import UIKit
import AVKit
import AVFoundation

class PlayerView: UIView {
    var player: AVPlayer? {
        get {
            return playerLayer.player
        }
        set {
            playerLayer.videoGravity = .resizeAspect
            playerLayer.player = newValue
        }
    }

    var playerLayer: AVPlayerLayer {
        return layer as! AVPlayerLayer
    }

    override static var layerClass: AnyClass {
        return AVPlayerLayer.self
    }
}

class CustomTableCell: UITableViewCell {
    let titleView = UILabel()
    let containerView = UIView()
    let playerView = PlayerView()
    required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)}
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        titleView.text = "Title"
        titleView.translatesAutoresizingMaskIntoConstraints = false

        contentView.clipsToBounds = true
        containerView.clipsToBounds = true
        contentView.addSubview(containerView)
        containerView.translatesAutoresizingMaskIntoConstraints = false
        //contentView.layoutMargins = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        var lg = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            containerView.topAnchor.constraint(equalTo: lg.topAnchor),
            containerView.leadingAnchor.constraint(equalTo: lg.leadingAnchor),
            containerView.trailingAnchor.constraint(equalTo: lg.trailingAnchor),
            containerView.bottomAnchor.constraint(equalTo: lg.bottomAnchor)
        ])

        containerView.addSubview(titleView)
        containerView.layoutMargins = UIEdgeInsets(top: 15, left: 17, bottom: 15, right: 17)
        lg = containerView.layoutMarginsGuide

        playerView.translatesAutoresizingMaskIntoConstraints = false
        containerView.addSubview(playerView)
        NSLayoutConstraint.activate([
            titleView.topAnchor.constraint(equalTo: lg.topAnchor),
            titleView.leadingAnchor.constraint(equalTo: lg.leadingAnchor),
            titleView.trailingAnchor.constraint(equalTo: lg.trailingAnchor),
//            titleView.bottomAnchor.constraint(equalTo: lg.bottomAnchor),

            playerView.topAnchor.constraint(equalTo: titleView.bottomAnchor),
            playerView.leadingAnchor.constraint(equalTo: lg.leadingAnchor),
            playerView.trailingAnchor.constraint(equalTo: lg.trailingAnchor),
            playerView.bottomAnchor.constraint(equalTo: lg.bottomAnchor)
        ])
    }
}

Я настроил UITableView в моем контроллере представления, но главное - это cellForRowAt UITableViewDataSource:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReuseableCell(withIdentifier: "cell") as! CustomTableCell
    let url = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
    let avPlayer = AVPlayer(url: url! as URL)
    cell.playerView.playerLayer.player = avPlayer
    return cell
}

Но я не вижу видео. Очевидно, что есть такая функция, как willLayoutSubviews или что-то в этом роде, но как бы я нарушил ограничение представления заголовка, чтобы ограничить его AVPlayerLayer, или что-то в этом роде, чтобы я мог посмотреть видео?

В общем, как бы я увидел, что AVPlayer или любой другой игрок внутри пользовательского UITableViewCell имеет другие виды автоматического макета?


Редактировать 1: Ответ, который @ugur дал правильно, так как AVPlayer должен изменить размер. Расширение представления с использованием leadngAnchor и trailingAnchor не может решить проблему, так как это было только расширение размера текущего представления.

Использование centerXAnchor, widthAnchor и heightAnchor будет работать. CenterXAnchor будет центром вашего игрока в поле зрения.

Ответы [ 2 ]

1 голос
/ 26 января 2020

Вы должны указать autolayout, как будет рассчитана высота playerView. Вы можете попробовать следующие варианты:

  1. установить постоянную высоту для playerView

    playerView.heightAnchor.constraint(equalToConstant: 100)
    
  2. или установить соотношение сторон для playerView

    playerView.heightAnchor.constraint(equalTo: playerView.widthAnchor, multiplier: 1.0)
    

Таким образом, autolayout будет знать, как позиционировать ваш playerView. в противном случае высота playerView будет равна 0.

Рекомендации:

Не создавайте AVPlayer в cellFor, вместо этого делайте это в init ячейки или awakeFromNib (если раскадровка используется). Так что AVPlayer тоже будет многоразовым. Просто сбросьте настройки с новым URL или playerItem. Вы также можете использовать воспроизведение или паузу в зависимости от вашего случая. Но только не воссоздайте AVPlayer каждый раз, когда вызывается cellFor.

0 голосов
/ 28 января 2020

Итак, ваша главная проблема в том, что вы не можете видеть своего игрока внутри клетки. Я изменил некоторые из вас код, а затем он также показывает и воспроизводит видео.

ПРИМЕЧАНИЕ. Это очень базовый c код, и я уверен, что вы сможете улучшить его в соответствии с вашими требованиями.

Ваш PlayerView остается таким же, как и в следующих изменениях. Я добавил новый метод configureFor, который будет получать только URL в качестве параметра и настройки проигрывателя.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableCell
    let url = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
    cell.configureFor(url!)
    return cell
}

Ниже приведен ваш код для ячейки. Здесь я переместил код настройки пользовательского интерфейса в общую функцию commonInit(), а затем использовал его следующим образом.

    class CustomTableCell: UITableViewCell {

    let titleView = UILabel()
    let containerView = UIView()
    let playerView = PlayerView()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }

    func commonInit() {
        titleView.text = "Title"
        titleView.translatesAutoresizingMaskIntoConstraints = false

        contentView.clipsToBounds = true
        containerView.clipsToBounds = true
        containerView.backgroundColor = .orange
        contentView.addSubview(containerView)
        containerView.translatesAutoresizingMaskIntoConstraints = false
        //contentView.layoutMargins = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        var lg = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            containerView.topAnchor.constraint(equalTo: lg.topAnchor),
            containerView.leadingAnchor.constraint(equalTo: lg.leadingAnchor),
            containerView.trailingAnchor.constraint(equalTo: lg.trailingAnchor),
            containerView.bottomAnchor.constraint(equalTo: lg.bottomAnchor)
        ])

        containerView.addSubview(titleView)
        containerView.layoutMargins = UIEdgeInsets(top: 15, left: 17, bottom: 15, right: 17)
        lg = containerView.layoutMarginsGuide

        playerView.translatesAutoresizingMaskIntoConstraints = false
        containerView.addSubview(playerView)
        NSLayoutConstraint.activate([
            titleView.topAnchor.constraint(equalTo: lg.topAnchor),
            titleView.leadingAnchor.constraint(equalTo: lg.leadingAnchor),
            titleView.trailingAnchor.constraint(equalTo: lg.trailingAnchor),
            //            titleView.bottomAnchor.constraint(equalTo: lg.bottomAnchor),

            playerView.topAnchor.constraint(equalTo: titleView.bottomAnchor),
            playerView.leadingAnchor.constraint(equalTo: lg.leadingAnchor),
            playerView.trailingAnchor.constraint(equalTo: lg.trailingAnchor),
            playerView.bottomAnchor.constraint(equalTo: lg.bottomAnchor)
        ])
    }

    func configureFor(_ url: URL) {
        let avPlayer = AVPlayer(url: url)
        self.playerView.playerLayer.player = avPlayer
        self.playerView.playerLayer.player?.play()
    }
}
...