今回実装すること
今回はアプリでもよくあるインライン再生を実装してみたいと思います。
実装する機能は次のとおりです。
・インライン再生
・画面上では一つの動画しか再生できない(一つ再生させればもう一つはポーズする)
完成イメージ
画面の構造
上記のように動画を貼りたいUIViewを用意してYTPlayerViewを継承させます。
その上にUIImageViewを動画のサムネイルとして配置し、さらに上からUIButtonを再生ボタンとして配置します。
実際のコード
まずは今回使うYouTubeSDKをインストールします
pod 'youtube-ios-player-helper'
次に実際にコードを見ていきましょう。
import UIKit
import youtube_ios_player_helper
class ViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var tableView: UITableView!
var playingVideos: [YTPlayerView] = []
// MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.rowHeight = 290
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
pauseVideo(cell as! Cell)
}
}
// MARK: - CellDelegate
extension ViewController: CellDelegate {
func pauseVideo(at: Int) {
playingVideos[at].pauseVideo()
removePlayingList()
}
func appendPlayingList(_ playerView: YTPlayerView) {
playingVideos.append(playerView)
}
func removePlayingList() {
if !playingVideos.isEmpty {
// 他に再生中の動画がある場合
playingVideos.remove(at: 0)
}
}
func isExist(_ playerView: YTPlayerView) {
if !playingVideos.isEmpty {
// 他に再生中の動画がある場合
pauseVideo(at: 0)
removePlayingList()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.appendPlayingList(playerView)
}
} else {
// 他に再生中の動画がない場合
appendPlayingList(playerView)
}
}
func pauseVideo(_ cell: Cell) {
cell.playerView.pauseVideo()
print("DEBUG: ビデオがストップしました")
}
}
コードの簡単な解説をしていきたいと思います。
今回は画面上では一つの動画しか再生されないようにするため他の動画を再生したら現在再生中の動画を止める必要があります。
そのため、再生中の動画をplayingVideosという配列で定義しておきます。
今回は配列を用意しているのですが、画面上で最大一つの動画しか再生させないため、最大値は1になります。
処理は再生している場合配列に1を入れ、一時停止または停止した場合、配列を空にします。
他の動画を再生する場合、現在配列が空かどうかを判定して、空であれば1を入れ、すでに1が入っている場合は再生中の動画があるということなので、その動画を一時停止し(配列を空にして)動画を再生(配列に1を入れる)といった流れです。
import UIKit
import AlamofireImage
import youtube_ios_player_helper
protocol CellDelegate: AnyObject {
func pauseVideo(_ cell: Cell)
func appendPlayingList(_ playerView: YTPlayerView)
func removePlayingList()
func isExist(_ playerView: YTPlayerView)
}
class Cell: UITableViewCell, YTPlayerViewDelegate {
// MARK: - Properties
@IBOutlet weak var playerView: YTPlayerView!
@IBOutlet weak var thumbnailImageView: UIImageView!
@IBOutlet weak var playButton: UIButton!
weak var delegate: CellDelegate?
// MARK: - Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
playerView.delegate = self
// 動画の読み込みを行う
// ビデオIDはyoutubeのurlの最後の部分を入れます。ex) https://www.youtube.com/watch?v=krVvD84IkQ8の場合はkrVvD84IkQ8
playerView.load(withVideoId: ビデオID, playerVars: ["playsinline": 1, "controls": 0, "modestbranding": 0, "autoplay": 1, "rel": 0, "enablejsapi": 1])
thumbnailImageView.af.setImage(withURL: URL(string: "https://img.youtube.com/vi/FzKUVEfxw44/0.jpg")!)
}
// MARK: - Actions
@IBAction func tapPlay(sender: UIButton) {
playerView.playVideo()
}
// MARK: - YTPlayerViewDelegate
// 動画の状態が変化したときに呼ばれるメソッド
func playerView(_ playerView: YTPlayerView, didChangeTo state: YTPlayerState) {
switch state {
case .ended:
delegate?.removePlayingList()
case .playing:
playButton.isHidden = true
thumbnailImageView.isHidden = true
delegate?.isExist(playerView)
case .paused:
playButton.isHidden = false
delegate?.removePlayingList()
case .buffering:
// 動画の読み込み中に呼ばれる
break
default:
break
}
}
}
こちらはcell側のコードです。
動画の状態が変化するとそれに準したdelegateが呼ばれるようになっています。
最後に
本記事は冗長な説明を省いて要点だけを説明しました。
これからもお時間がない人でもサクッと読んでいただけますと幸いです。