🎅

[Flutter] youtube_player_iframeで再生機能をカスタマイズ

に公開

はじめに

本記事は Flutter Advent Calendar 2024 の19日目の記事です。
youtube_player_iframe について調べたことをまとめました。
再生する機能だけならすでにまとめてくれている方がたくさんいますが、アプリを開発するにあたってもう少し踏み込んでカスタマイズしたかったので、少し深掘りして説明できればと思います。
主に公式のドキュメントサンプルを参考にしています。
バージョンは2024年12月時点最新の 5.2.1 を使っています。

動画再生

まずは、一つの動画を再生する方法です。
これには YouTubePlayerController と YouTubePlayer を使います。
YoutubePlayerController は再生機能の設定をするコントローラー、YoutubePlayer は動画を再生する Widget になります。
initState() で YoutubePlayerController を作成します。
YoutubePlayerParams のフィールドを設定してカスタマイズすることができますが、まずはデフォルトの状態で設定してみます。
一つの動画を読み込むには loadVideoById() で Youtube の VideoID を指定します。
サンプルは下記のようになります。

import 'package:flutter/material.dart';
import 'package:youtube_player_iframe/youtube_player_iframe.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: YoutubePlayerArea(),
    );
  }
}

class YoutubePlayerArea extends StatefulWidget {
  const YoutubePlayerArea({super.key});

  
  State<YoutubePlayerArea> createState() => _YoutubePlayerAreaState();
}

class _YoutubePlayerAreaState extends State<YoutubePlayerArea> {
  late YoutubePlayerController _controller;

  
  void initState() {
    super.initState();

    _controller = YoutubePlayerController(
      params: const YoutubePlayerParams(),
    );

    _controller.loadVideoById(
      videoId: 'pbQQAwSQUX4',
    );
  }

  
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        YoutubePlayer(
            controller: _controller
        ),
      ],
    );
  }
}

loadVideoById() では再生する開始の秒数と停止の秒数を指定することができます。
これによって任意の範囲だけ動画を再生することも可能になります。

_controller.loadVideoById(
  videoId: 'pbQQAwSQUX4',
  startSeconds: 60,
  endSeconds: 75,
);

次に YoutubePlayerParams の値を変更してみます。
YoutubePlayerParams では主に下記のような値を設定することができます。

  • showControls
    公式のYoutubeでは動画上に再生ボタンやミュートボタン、再生速度などを設定するボタンが表示されると思います。これはその表示をするかどうかの設定です。デフォルトはtrueです。
  • mute
    ミュートを設定します。デフォルトはfalseです。
  • showFullscreenButton
    Youtube公式にある、フルスクリーン表示するボタンの表示設定です。デフォルトはfalseです。
    ※YoutubePlayerではなくYoutubePlayerScaffoldを使う必要があります。
  • loop
    ループ再生の設定です。デフォルトはfalseです。
    _controller = YoutubePlayerController(
      params: const YoutubePlayerParams(
          showControls: false,
          mute: true,
          showFullscreenButton: true,
          loop: true,
      ),
    );

メタデータの取得

YoutubeValueBuilder を使うと、YoutubePlayerControlle rやYoutubePlayerValue のプロパティを取得できます。
変更を監視して最新の値を取得します。
YoutubePlayerValue には value からアクセスします。

// YoutubePlayerArea
  
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        YoutubePlayer(
            controller: _controller
        ),

        YoutubeValueBuilder(
            controller: _controller,
            builder: (context, value) {
              return Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text('チャンネル名: ${value.metaData.author}'),
                  Text('タイトル: ${value.metaData.title}'),
                  Text('ビデオID: ${value.metaData.videoId}'),
                  Text('動画秒数: ${value.metaData.duration.toString()}'),
                  Text('再生速度: ${value.playbackRate.toString()}'),
                  Text('ステータス: ${value.playerState.name}'),

                  Text('再生時間: ${_controller.currentTime}'),
                  Text('ミュート: ${_controller.isMuted}'),
                  Text('ボリューム: ${_controller.volume}'),
                ],
              );
            }
        )
      ],
    );
  }

Provider

ここまで一つのWidgetに全て実装してきましたが、YoutubePlayerControllerProvider という Provider の仕組みも用意されているので、子Widgetに YoutubePlayerController を渡すことができます。

値を取得するコードを Provider を使った方法に置き換えてみます。
YoutubePlayerController には context.ytController でアクセスします。YoutubePlayerValue は先ほどと同様に value に入っています。

// YoutubePlayerArea
  
  Widget build(BuildContext context) {
    return YoutubePlayerControllerProvider(
      controller: _controller,
      child: Builder(
          builder: (context){
            return Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                YoutubePlayer(
                    controller: context.ytController
                ),
                const YoutubeInfo(),
              ],
            );
          }
      ),
    );
  }

  ...

class YoutubeInfo extends StatelessWidget {
  const YoutubeInfo({super.key});

  
  Widget build(BuildContext context) {
    return YoutubeValueBuilder(
        builder: (context, value) {
          return Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Text('チャンネル名: ${value.metaData.author}'),
              Text('タイトル: ${value.metaData.title}'),
              Text('ビデオID: ${value.metaData.videoId}'),
              Text('動画秒数: ${value.metaData.duration.toString()}'),
              Text('再生速度: ${value.playbackRate.toString()}'),
              Text('ステータス: ${value.playerState.name}'),

              Text('再生時間: ${context.ytController.currentTime}'),
              Text('ミュート: ${context.ytController.isMuted}'),
              Text('ボリューム: ${context.ytController.volume}'),
            ],
          );
        }
    );
  }
}

値の設定

YoutubePlayerController のメソッドで、再生機能の設定が可能です。
プレイリストを再生するサンプルを実装してみます。
プレイリストの再生には、loadVideoById() ではなく loadPlaylist() を使います。

// YoutubePlayerArea - initState()
    List<String> videoIds = [
      'pbQQAwSQUX4',
      'i6d3K6ln-d4',
      'a7cwqxmn7rY',
      'l9IAr7WY-Xk',
      'cE8wVmwY7VY',
    ];

    _controller.loadPlaylist(
      list: videoIds,
      listType: ListType.playlist,
    );

下記が YoutubePlayerController に対して値を設定していくサンプルになります。
こちらも YoutubePlayerControllerProvider と YoutubeValueBuilder を使っています。

// YoutubeInfo
  
  Widget build(BuildContext context) {
    bool isShuffle = false;
    return YoutubeValueBuilder(
        builder: (context, value) {
          return Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  IconButton( // 一つ前の動画を再生する
                    onPressed: () {
                      context.ytController.previousVideo();
                    },
                    icon: Icon(Icons.skip_previous),
                  ),
                  IconButton( // 再生と一時停止を交互に
                    onPressed: () {
                      value.playerState == PlayerState.playing
                          ? context.ytController.pauseVideo()
                          : context.ytController.playVideo();
                    },
                    icon: value.playerState == PlayerState.playing
                        ? Icon(Icons.pause)
                        : Icon(Icons.play_arrow),
                  ),
                  IconButton( // 次のビデオを再生する
                    onPressed: () {
                      context.ytController.nextVideo();
                    },
                    icon: Icon(Icons.skip_next),
                  ),
                  IconButton( // プレイリストをシャッフルして再生する
                      onPressed: () {
                        isShuffle = !isShuffle;
                        context.ytController.setShuffle(shufflePlaylists: isShuffle);
                      },
                      icon: isShuffle
                          ? Icon(Icons.shuffle_on_rounded)
                          : Icon(Icons.shuffle_rounded)
                  ),
                ],
              )
            ],
          );
        }
    );
  }

まとめ

youtube_player_iframe について説明してきました。
思っていた以上にカスタマイズができそうで、作りたいアプリの要件を満たせそうです。
これから年末年始のお休みに入るので、これを使ったアプリの開発に挑戦してみたいと思います。

Discussion