跳至主要内容

播放和暂停视频

在应用程序开发中,播放视频是一项常见的任务,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 文件位于 <project root>/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,将以下内容添加到位于 <project root>/ios/Runner/Info.plistInfo.plist 文件中。

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

macOS

#

如果您使用基于网络的视频,请 添加 com.apple.security.network.client 权限

Web

#

Flutter 网页版**不支持** dart:io,因此请避免使用该插件的 VideoPlayerController.file 构造函数。使用此构造函数会尝试创建一个抛出 UnimplementedErrorVideoPlayerController.file

不同的网络浏览器可能具有不同的视频播放功能,例如支持的格式或自动播放。请查看 video_player_web 包以获取更多特定于网络的信息。

VideoPlayerOptions.mixWithOthers 选项目前还无法在网络版中实现。如果您在网络版中使用此选项,它将被静默忽略。

3. 创建并初始化 VideoPlayerController

#

现在您已安装了 video_player 插件并具有正确的权限,请创建一个 VideoPlayerControllerVideoPlayerController 类允许您连接到不同类型的视频并控制播放。

在播放视频之前,您还必须初始化控制器。这将建立与视频的连接并为播放准备控制器。

要创建并初始化 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,
        ),
      ),
    );
  }
}