動画再生はアプリ開発ではよくある作業で、Flutterアプリも例外ではありません。
動画を再生する為に、Flutterチームはvideo_player プラグインを提供しています。
video_player プラグインを使って、ファイルシステム、アセット、またはインターネットから保存された動画を再生することができます。
制限事項
現時点では、video_player プラグインは Linux と Windows では動作しません。
詳しくは、video_player パッケージをご覧ください。
iOSでは、video_playerプラグインは AVPlayer を使って再生を処理します。Androidでは ExoPlayer を使用します。
ここでは、video_player パッケージを使用して、基本的な再生と一時停止のコントロールを使ってインターネットからビデオをストリーミングする方法を示します。
- video_player パッケージの依存関係追加
- アプリへの権限追加
- VideoPlayerController による初期化
- ビデオプレイヤーの表示
- ビデオの再生と一時停止
1.video_player パッケージの依存関係追加
2.アプリへの権限追加
flutter pub add video_player
2-1.Android
2-2.iOS
2-3.macOS
2-4.Web
3.VideoPlayerController による初期化
VideoPlayerController を作成し、初期化するプロセスについて触れています。
VideoPlayerController は、ビデオ再生に必要なコントローラです。これにより、ビデオファイルを再生、停止、シーク(特定の位置に移動)などが可能になります。動画を再生するためには、コントローラの初期化が必要です。
初期化プロセスでは、動画の読み込みが行われ、コントローラがビデオの操作準備を整えます。
3-1.手順
- StatefulWidget を作成
状態管理が必要なため、StatefulWidget を使用します。 - State クラスにコントローラと Future 変数を追加
VideoPlayerController とその初期化処理を保持する Future を定義します。 - initState でコントローラを作成し初期化
initState メソッド内で VideoPlayerController を初期化し、動画の再生準備を行います。 - dispose メソッドでリソース解放
使用したコントローラを適切に破棄して、リソースを解放します。
3-2.サンプルコード
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart'; // ビデオプレイヤーのパッケージをインポート
class VideoPlayerScreen extends StatefulWidget {
const VideoPlayerScreen({super.key});
@override
State<VideoPlayerScreen> createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
// VideoPlayerController インスタンスを保持
late VideoPlayerController _controller;
// 動画の初期化状態を追跡するための Future
late Future<void> _initializeVideoPlayerFuture;
@override
void initState() {
super.initState();
// VideoPlayerController を作成して、ネットワーク上の動画を再生
_controller = VideoPlayerController.networkUrl(
Uri.parse(
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
),
);
// コントローラの初期化を Future に保存
_initializeVideoPlayerFuture = _controller.initialize();
}
@override
void dispose() {
// 使用後、リソースを解放するためにコントローラを破棄
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// ビルドメソッドで動画を表示
return FutureBuilder(
future: _initializeVideoPlayerFuture, // 初期化状態を確認
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// 動画が初期化されていれば VideoPlayer ウィジェットを表示
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
);
} else {
// 初期化中はローディングインジケータを表示
return const Center(child: CircularProgressIndicator());
}
},
);
}
}
4.ビデオプレイヤーの表示
ビデオを表示するためには、Flutter の video_player パッケージが提供する VideoPlayer ウィジェットを使用します。このウィジェットは、事前に VideoPlayerController によって初期化されたビデオを表示します。しかし、ビデオは通常、固定されたアスペクト比(例えば、16:9 や 4:3)で表示されるため、適切な比率で表示する必要があります。そのために、AspectRatio ウィジェットを使って、正しいアスペクト比でビデオが表示されるようにします。
また、コントローラの初期化が完了するまでに時間がかかるため、FutureBuilder を使って初期化が完了するまでローディングスピナー(CircularProgressIndicator)を表示します。この方法で、初期化中にユーザに何らかのフィードバックを提供し、初期化が終わったらビデオを再生できるようにします。
FutureBuilder(
//コントローラの初期化が完了するまで待つ
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
//コントローラの初期化が完了した場合、ビデオのアスペクト比に合わせて表示
return AspectRatio(
//動画のアスペクト比に合わせる
aspectRatio: _controller.value.aspectRatio,
//VideoPlayer ウィジェットでビデオを表示
child: VideoPlayer(_controller),
);
} else {
//コントローラの初期化中はローディングスピナーを表示
return const Center(
child: CircularProgressIndicator(),
);
}
},
)
- FutureBuilder の使用
VideoPlayerController の初期化は非同期で行われるため、FutureBuilder を使って初期化が完了するまで UI にローディングスピナーを表示します。これにより、初期化完了後にビデオをスムーズに表示できます。 - AspectRatio ウィジェットの使用
VideoPlayer ウィジェットはデフォルトでは可能な限り多くのスペースを使用しますが、動画は固定されたアスペクト比で表示する必要があるため、AspectRatio ウィジェットを使って、正しいプロポーションでビデオを表示します。 - 初期化が完了していないときの処理
snapshot.connectionState が ConnectionState.done でない場合、コントローラがまだ初期化されていないことを意味するため、その間はローディングスピナーを表示してユーザーに待機状態を伝えます。
このコードによって、ビデオが正しく初期化され、適切なアスペクト比で表示されることが保証されます。また、非同期処理による初期化の遅延があっても、ローディングインジケータを使ってユーザーに良好な体験を提供できます。
5.ビデオの再生と一時停止
ここでは、ビデオの再生と一時停止を実装します。
VideoPlayerController の play() メソッドを呼び出すと再生が始まり、pause() メソッドを呼び出すとビデオが一時停止します。
FloatingActionButton(
onPressed: () {
//`setState` の中で再生または一時停止を切り替える。
setState(() {
if (_controller.value.isPlaying) {
//ビデオが再生中なら、一時停止
_controller.pause();
} else {
//ビデオが一時停止中なら、再生開始
_controller.play();
}
});
},
//ビデオの状態に応じてアイコンを切り替える。
child: Icon(
//再生中なら pause アイコン、一時停止中なら play アイコンを表示
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
)
- 再生と一時停止のトグル
- setState() を使って、ビデオの状態(再生中か一時停止中か)に応じて UI を更新します。
_controller.value.isPlaying を使って、ビデオが再生中かどうかを確認します。isPlaying が true の場合はビデオを一時停止し、false の場合はビデオを再生します。
- setState() を使って、ビデオの状態(再生中か一時停止中か)に応じて UI を更新します。
- アイコンの変更
- ビデオの再生状態に基づいて、FloatingActionButton のアイコンを切り替えます。再生中なら pause アイコンが表示され、一時停止中なら play_arrow アイコンが表示されます。
- ユーザー操作に応じた再生/一時停止の切り替え
- ユーザーがボタンをタップするたびに、ビデオの再生と一時停止を切り替えることができます。これは、シンプルかつ直感的なビデオプレーヤー操作を提供します。
このコードは、FloatingActionButton を使ってビデオの再生と一時停止を制御する仕組みを実装しています。ユーザーがボタンをタップすると、現在のビデオの状態に応じて再生または一時停止が行われ、アイコンもそれに応じて更新されます。
6.サンプルコード
import 'dart:async';
import 'package:flutter/material.dart';
//ビデオ再生のためのパッケージ
import 'package:video_player/video_player.dart';
//アプリのエントリーポイント、VideoPlayerApp ウィジェットを実行する。
void main() => runApp(const VideoPlayerApp());
class VideoPlayerApp extends StatelessWidget {
const VideoPlayerApp({super.key});
@override
Widget build(BuildContext context) {
//MaterialApp ウィジェットでアプリ全体の設定を行い、
//VideoPlayerScreen を表示する
return const MaterialApp(
title: 'Video Player Demo',
home: VideoPlayerScreen(),
);
}
}
//動画を再生するための StatefulWidget
class VideoPlayerScreen extends StatefulWidget {
const VideoPlayerScreen({super.key});
@override
State<VideoPlayerScreen> createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
//ビデオプレーヤーを制御するコントローラ
late VideoPlayerController _controller;
//コントローラの初期化が完了するのを待つための Future
late Future<void> _initializeVideoPlayerFuture;
@override
void initState() {
super.initState();
//ビデオプレーヤーコントローラを作成しインターネット動画再生の設定をする。
//インターネットからビデオを再生するために
//VideoPlayerController.networkUrl を使用しています。
//他にも、ローカルのアセットやファイルからビデオを再生する方法もあります。
_controller = VideoPlayerController.networkUrl(
Uri.parse(
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
),
);
//ビデオプレーヤーの初期化を実行し、その結果の Future を保存する
//initialize() メソッドを使ってビデオの準備を行い、
//Future を使って初期化が完了するまで待機します。
_initializeVideoPlayerFuture = _controller.initialize();
//動画をループ再生に設定する
_controller.setLooping(true);
}
@override
void dispose() {
//コントローラを dispose してリソースを解放する。
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Butterfly Video'), //アプリバーのタイトル
),
//FutureBuilder によりビデオ初期化完了までローディングスピナを表示する
body: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
//ビデオプレーヤーの初期化が完了した場合
return AspectRatio(
//ビデオのアスペクト比を調整する
aspectRatio: _controller.value.aspectRatio,
//VideoPlayer ウィジェットを使ってビデオを表示する
child: VideoPlayer(_controller),
);
} else {
//初期化中はローディングスピナーを表示
return const Center(
//ローディングスピナー
child: CircularProgressIndicator(),
);
}
},
),
//再生中かどうかに応じて、FloatingActionButton
//のアイコンが再生 (play_arrow) または一時停止 (pause)
//に切り替わります。
floatingActionButton: FloatingActionButton(
onPressed: () {
//ボタンが押された際、ビデオの再生/一時停止を切り替える
setState(() {
if (_controller.value.isPlaying) {
//再生中なら一時停止
_controller.pause();
} else {
//一時停止中なら再生
_controller.play();
}
});
},
//ビデオの再生状態に応じてアイコンを切り替える
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}