跳到主内容

播放和暂停视频

如何使用 video_player 插件。

播放视频是应用开发中的常见任务,Flutter 应用也不例外。为了播放视频,Flutter 团队提供了 video_player 插件。你可以使用 video_player 插件来播放存储在文件系统中的视频、资源文件(asset)中的视频,或来自互联网的视频。

在 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

#

<application> 定义之后,将以下权限添加到 AndroidManifest.xml 文件中。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 授权(entitlement)

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://github.fluttercn.cn/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://github.fluttercn.cn/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,
        ),
      ),
    );
  }
}