跳到主內容

播放和暫停影片

如何使用 video_player 外掛。

在應用程式開發中,播放影片是一項常見任務,Flutter 應用程式也不例外。為了播放影片,Flutter 團隊提供了 video_player 外掛。你可以使用 video_player 外掛播放儲存在檔案系統、作為資源或從網際網路上的影片。

在 iOS 上,video_player 外掛使用 AVPlayer 來處理播放。在 Android 上,它使用 ExoPlayer

本教程演示瞭如何使用 video_player 包透過以下步驟從網際網路上流式傳輸影片,並使用基本的播放和暫停控制元件

  1. 新增 video_player 依賴項。
  2. 為你的應用新增許可權。
  3. 建立並初始化 VideoPlayerController
  4. 顯示影片播放器。
  5. 播放和暫停影片。

1. 新增 video_player 依賴項

#

本教程依賴於一個 Flutter 外掛:video_player。首先,將此依賴項新增到你的專案中。

要將 video_player 包新增為依賴項,請執行 flutter pub add

flutter pub add video_player

2. 為你的應用新增許可權

#

接下來,更新你的 androidios 配置,以確保你的應用具有從網際網路上流式傳輸影片的正確許可權。

Android

#

AndroidManifest.xml 檔案中,緊接在 <application> 定義之後新增以下許可權。AndroidManifest.xml 檔案位於 <專案根目錄>/android/app/src/main/AndroidManifest.xml

xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application ...>

    </application>

    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

iOS

#

對於 iOS,將以下內容新增到位於 <專案根目錄>/ios/Runner/Info.plistInfo.plist 檔案中。

xml
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

macOS

#

如果你使用基於網路的影片,新增 com.apple.security.network.client 許可權

Web

#

Flutter web 不支援 dart:io,因此請避免使用外掛的 VideoPlayerController.file 建構函式。使用此建構函式會嘗試建立一個VideoPlayerController.file,從而引發 UnimplementedError

不同的 Web 瀏覽器可能具有不同的影片播放功能,例如支援的格式或自動播放。請檢視 video_player_web 包以獲取更多 Web 特定的資訊。

目前,VideoPlayerOptions.mixWithOthers 選項無法在 Web 上實現。如果在 Web 上使用此選項,它將被靜默忽略。

3. 建立並初始化 VideoPlayerController

#

現在你已經安裝了具有正確許可權的 video_player 外掛,建立一個 VideoPlayerControllerVideoPlayerController 類允許你連線到不同型別的影片並控制播放。

在播放影片之前,你還必須 initialize 控制器。這將建立與影片的連線併為播放準備控制器。

要建立並初始化 VideoPlayerController,請執行以下操作

  1. 建立一個帶有伴隨 State 類的 StatefulWidget
  2. 將變數新增到 State 類中以儲存 VideoPlayerController
  3. 將變數新增到 State 類中以儲存從 VideoPlayerController.initialize 返回的 Future
  4. initState 方法中建立並初始化控制器
  5. dispose 方法中釋放控制器
dart
class VideoPlayerScreen extends StatefulWidget {
  const VideoPlayerScreen({super.key});

  @override
  State<VideoPlayerScreen> createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  late VideoPlayerController _controller;
  late Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    super.initState();

    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.networkUrl(
      Uri.parse(
        'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
      ),
    );

    _initializeVideoPlayerFuture = _controller.initialize();
  }

  @override
  void dispose() {
    // Ensure disposing of the VideoPlayerController to free up resources.
    _controller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // Complete the code in the next step.
    return Container();
  }
}

4. 顯示影片播放器

#

現在,顯示影片。video_player 外掛提供了 VideoPlayer 部件來顯示由 VideoPlayerController 初始化影片。預設情況下,VideoPlayer 部件佔據儘可能多的空間。這通常不適合影片,因為它們旨在以特定的縱橫比顯示,例如 16x9 或 4x3。

因此,將 VideoPlayer 部件包裝在 AspectRatio 部件中,以確保影片具有正確的比例。

此外,你必須在 _initializeVideoPlayerFuture() 完成後顯示 VideoPlayer 部件。使用 FutureBuilder 顯示載入微調器,直到控制器完成初始化。注意:初始化控制器不會開始播放。

dart
// Use a FutureBuilder to display a loading spinner while waiting for the
// VideoPlayerController to finish initializing.
FutureBuilder(
  future: _initializeVideoPlayerFuture,
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.done) {
      // If the VideoPlayerController has finished initialization, use
      // the data it provides to limit the aspect ratio of the video.
      return AspectRatio(
        aspectRatio: _controller.value.aspectRatio,
        // Use the VideoPlayer widget to display the video.
        child: VideoPlayer(_controller),
      );
    } else {
      // If the VideoPlayerController is still initializing, show a
      // loading spinner.
      return const Center(child: CircularProgressIndicator());
    }
  },
)

5. 播放和暫停影片

#

預設情況下,影片從暫停狀態開始。要開始播放,請呼叫 VideoPlayerController 提供的 play() 方法。要暫停播放,請呼叫 pause() 方法。

對於本示例,將 FloatingActionButton 新增到你的應用中,該按鈕根據情況顯示播放或暫停圖示。當用戶點選按鈕時,如果影片當前已暫停,則播放影片;如果影片正在播放,則暫停影片。

dart
FloatingActionButton(
  onPressed: () {
    // Wrap the play or pause in a call to `setState`. This ensures the
    // correct icon is shown.
    setState(() {
      // If the video is playing, pause it.
      if (_controller.value.isPlaying) {
        _controller.pause();
      } else {
        // If the video is paused, play it.
        _controller.play();
      }
    });
  },
  // Display the correct icon depending on the state of the player.
  child: Icon(
    _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
  ),
)

完整示例

#
import 'dart:async';

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

void main() => runApp(const VideoPlayerApp());

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Video Player Demo',
      home: VideoPlayerScreen(),
    );
  }
}

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

  @override
  State<VideoPlayerScreen> createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  late VideoPlayerController _controller;
  late Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    super.initState();

    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.networkUrl(
      Uri.parse(
        'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
      ),
    );

    // Initialize the controller and store the Future for later use.
    _initializeVideoPlayerFuture = _controller.initialize();

    // Use the controller to loop the video.
    _controller.setLooping(true);
  }

  @override
  void dispose() {
    // Ensure disposing of the VideoPlayerController to free up resources.
    _controller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Butterfly Video')),
      // Use a FutureBuilder to display a loading spinner while waiting for the
      // VideoPlayerController to finish initializing.
      body: FutureBuilder(
        future: _initializeVideoPlayerFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            // If the VideoPlayerController has finished initialization, use
            // the data it provides to limit the aspect ratio of the video.
            return AspectRatio(
              aspectRatio: _controller.value.aspectRatio,
              // Use the VideoPlayer widget to display the video.
              child: VideoPlayer(_controller),
            );
          } else {
            // If the VideoPlayerController is still initializing, show a
            // loading spinner.
            return const Center(child: CircularProgressIndicator());
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // Wrap the play or pause in a call to `setState`. This ensures the
          // correct icon is shown.
          setState(() {
            // If the video is playing, pause it.
            if (_controller.value.isPlaying) {
              _controller.pause();
            } else {
              // If the video is paused, play it.
              _controller.play();
            }
          });
        },
        // Display the correct icon depending on the state of the player.
        child: Icon(
          _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
        ),
      ),
    );
  }
}