Flutter_学习记录_video_player、chewie 播放视频

news2025/4/22 3:37:48

1. video_player 视频播放

插件地址:https://pub.dev/packages/video_player

  1. 添加插件
    在这里插入图片描述
  2. 导入头文件
import 'package:video_player/video_player.dart';
  1. Android配置(iOS不用配置)

修改这个文件:/android/app/src/main/AndroidManifest.xml;
添加下面的配置:

<uses-permission android:name="android.permission.INTERNET"/>
  1. 添加核心代码

初始化播放器:

Uri url = Uri.parse("https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4");
    _videoPlayerController = VideoPlayerController.networkUrl(url);
    _videoPlayerController.initialize().then((_){
      print("播放器初始化完成");
      // 添加播放器的监听
      _videoPlayerController.addListener(_onVideoChange);
      // 设置自动播放
      _videoPlayerController.play();
      _isPlaying = true;
      setState(() {
        print("111111");
      });
    });

添加播放器的视图:

return VideoPlayer(_videoPlayerController);

退出页面时,需要销毁播放器:

 
  void dispose() {
    _videoPlayerController.dispose();
    super.dispose();
  }
  1. 完整代码
import 'dart:async';

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

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

  
  State<VideoPlayerDemo> createState() => _VideoPlayerDemoState();
}

class _VideoPlayerDemoState extends State<VideoPlayerDemo> {

  
  late VideoPlayerController _videoPlayerController;
  bool _isPlaying = false;
  double _progress = 0.0;

  // 添加播放状态的订阅,避免每次调用setState 重刷页面
  late StreamController _isPlayingController;
  // 添加播放进度的订阅,避免每次调用setState 重刷页面
  late StreamController _progressController;

  
  void initState() {
    super.initState();

    _isPlayingController = StreamController.broadcast();
    _progressController = StreamController.broadcast();

    Uri url = Uri.parse("https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4");
    _videoPlayerController = VideoPlayerController.networkUrl(url);
    _videoPlayerController.initialize().then((_){
      print("播放器初始化完成");
      // 添加播放器的监听
      _videoPlayerController.addListener(_onVideoChange);
      // 设置自动播放
      _videoPlayerController.play();
      _isPlaying = true;
      setState(() {

      });
    });
  }

  
  void dispose() {
    _videoPlayerController.dispose();
    _isPlayingController.close();
    _progressController.close();

    super.dispose();
  }

  // 自定义播放器的监听回调的方法
  void _onVideoChange() {
    print("播放器的监听回调");
      if (_videoPlayerController.value.isInitialized) {
        final isPlaying = _videoPlayerController.value.isPlaying;
        if (isPlaying != _isPlaying) {
          _isPlaying = isPlaying;
          _isPlayingController.sink.add(_isPlaying);
        }

        // 更新播放进度
        final position = _videoPlayerController.value.position;
        final duration = _videoPlayerController.value.duration;
        if (duration != null) {
            _progress = position.inMilliseconds / duration.inMilliseconds;
            print("进度 = $_progress");
            _progressController.sink.add(_progress);
        }

        // 检查视频是否播放完毕
        if (position >= duration) {
          print('Video has completed playing.');
          _videoPlayerController.seekTo(Duration.zero); // 重置到开始位置
          _videoPlayerController.pause(); // 暂停播放
          _isPlaying = false;
          _isPlayingController.add(_isPlaying);
        }
      }
  }

  // 播放器的视图
  Widget _palyerViewWidget() {
    if (_videoPlayerController.value.isInitialized) {
      // 初始化成功
      return AspectRatio(
        aspectRatio: _videoPlayerController.value.aspectRatio,
        child: Stack(
          children: [
            // 播放器
            VideoPlayer(_videoPlayerController),
            // 添加进度条
            Align(
              alignment: Alignment.bottomCenter,
              child: _progressWidget(),
            )
          ],
        )
      );
    } else {
      // loading视图
      return CircularProgressIndicator();
    }
  }

  // 进度条
  Widget _progressWidget() {
    // 进度条变化比较频繁:用 StreamBuilder 减少内存的消耗
    return  StreamBuilder(
      stream: _progressController.stream, 
      builder: (context, snapshot) {
        print("更新进度条");
        return SizedBox(
          height: 35,
          child: Slider(
            value: _progress,
            onChanged: (value) {
              print("onChanged");
              setState(() {
                _videoPlayerController.seekTo(
                  Duration(
                    milliseconds: (value * _videoPlayerController.value.duration.inMilliseconds).round()
                  )
                );
              });
            },
          ),
        );
      });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Video_Player_demo"),
      ),
      body: Center(
        child: _palyerViewWidget(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          if (_isPlaying) {
            // 正在播放
            _videoPlayerController.pause();
            _isPlaying = false;
          } else {
             _videoPlayerController.play();
             _isPlaying = true;
          }
          _isPlayingController.add(_isPlaying);
        },
        // 这个按钮变化比较频繁:用 StreamBuilder 减少内存的消耗
        child: StreamBuilder(
          stream: _isPlayingController.stream, 
          builder: (context, snapshot) {
            return Icon(
              _isPlaying ? Icons.pause : Icons.play_arrow
            );
          }),
      ),
    );
  }
}
  1. 效果图如下:
    在这里插入图片描述

2. chewie 播放视频

在 Flutter 里官方提供了一个 video_player插件可以播放视频,但video_player有一些局限性:没法控制底部播放进度等。
所以可以用另外一个三方的视频播放库chewie
chewie是一个非官方的第三方视频播放组件,看起来好像是基于 HTML5 播放的组件。
chewie 相对 video_player 来说,有控制栏和全屏的功能
Chewie 使用 video_player 引擎并将其包裹在友好的 Material 或 Cupertino UI中!

插件地址:https://pub.dev/packages/chewie

  1. 引入插件
    chewie基于video_player,所以要使用chewie必须配置video_player
    在这里插入图片描述
  2. 导入头文件
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
  1. Android配置(iOS不用配置)

修改这个文件:/android/app/src/main/AndroidManifest.xml;
添加下面的配置:

<uses-permission android:name="android.permission.INTERNET"/>
  1. 核心代码
import 'package:chewie/chewie.dart';
import 'package:video_player/video_player.dart';

final videoPlayerController = VideoPlayerController.networkUrl(Uri.parse(
    'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4'));

await videoPlayerController.initialize();

final chewieController = ChewieController(
  videoPlayerController: videoPlayerController,
  autoPlay: true,
  looping: true,
);

final playerWidget = Chewie(
  controller: chewieController,
);

退出页面时,需要销毁播放器:

 
  void dispose() {
    _videoPlayerController.dispose();
    _chewieController.dispose();
    super.dispose();
  }
  1. 完整代码
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';

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

  
  State<ChewieDemo> createState() => _ChewieDemoState();
}

class _ChewieDemoState extends State<ChewieDemo> {

  late VideoPlayerController _videoPlayerController;
  late ChewieController _chewieController;

  
  void initState() {
    super.initState();
    // 初始化播放器
    _initVideo();
  }

  
  void dispose() {
    _videoPlayerController.dispose();
    _chewieController.dispose();
    super.dispose();
  }

  // 初始化播放器
  void _initVideo() async {
    Uri url = Uri.parse(
      "https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4"
    );
    _videoPlayerController = VideoPlayerController.networkUrl(url);
    await _videoPlayerController.initialize();

    _chewieController = ChewieController(
      videoPlayerController: _videoPlayerController,
      aspectRatio: _videoPlayerController.value.aspectRatio,
      autoPlay: true,
      looping: false
    );
    
    setState(() {});
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Chewie demo-在线播放视频"),
      ),
      body: Center(
        child: _videoPlayerController.value.isInitialized ? AspectRatio(
          aspectRatio: _videoPlayerController.value.aspectRatio,
          child: Chewie(controller: _chewieController),
        ) : CircularProgressIndicator(),
      ),
    );
  }
}
  1. 效果图:
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2314523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL】增删改查进阶

目录 一、数据库约束 约束类型 NULL约束&#xff1a;非空约束 UNIQUE&#xff1a;唯一约束 DEFAULT&#xff1a;默认值约束 PRIMARY KEY&#xff1a;主键约束 FOREIGN KEY&#xff1a;外键约束 二、表的设计 三、新增 四、查询 聚合查询 聚合函数 GROUP BY子句 HA…

静态时序分析:SDC约束命令set_ideal_latency详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 当使用set_ideal_network命令将当前设计中的一组端口或引脚标记为理想网络源后&#xff0c;理想属性会沿着组合逻辑进行传播&#xff0c;理想网络中的线网和单元…

达梦数据库查看字符集编码

select SF_GET_UNICODE_FLAG(); 返回 0 代表数据库字符集编码为 GB18030 1 代表数据库字符集编码为 UTF-8 2 代表数据库字符集编码为韩文字符集 EUC-KR

Pac-Man(吃豆人) 游戏

目录 前言 1. Pygame游戏开发基础 1.1 Pygame简介 1.2 游戏开发基本概念 1.3 Pygame核心模块介绍 2. 游戏设计与规划 2.1 游戏规则设计 2.2 游戏对象规划 2.3 技术方案选择 3. 创建游戏窗口与初始化 3.1 初始化Pygame环境 3.2 设置游戏窗口 3.3 定义颜色和游戏参数…

【Spring】@PostConstruct详解

在 Java 开发中&#xff0c;尤其是在基于 Spring 框架的项目里&#xff0c;我们常常会遇到需要在对象创建并完成依赖注入后&#xff0c;执行一些初始化操作的场景。PostConstruct注解正是为解决此类问题而诞生的&#xff0c;它为我们提供了一种便捷且优雅的方式来处理对象的初始…

OEM SQL Details and Session Details 5s 或者parallel 才会在sql monitor显示

从企业管理器 13.4 版本更新 10 (RU10) 开始&#xff0c;ASH Analytics 的 SQL 详细信息和会话详细信息深入屏幕已更新为使用 Oracle JET UI。 在 Ash Analytics 中&#xff0c;单击左下角区域中“热门 SQL”中的 SQL ID 即可深入了解 SQL 详细信息。 单击右下角“热门会话”区…

JSAR 基础 1.2.1 基础概念_空间小程序

JSAR 基础 1.2.1 基础概念_空间小程序 空间空间自由度可嵌入空间空间小程序 最新的技术进展表明&#xff0c;官网之前的文档准备废除了&#xff0c;基于xsml的开发将退出历史舞台&#xff0c;three.js和普通web结合的技术将成为主导。所以后续学习请移步three.js学习路径&#…

Spring Security的作用

一、概述 Spring Security是一个框架&#xff0c;提供认证&#xff08;authentication&#xff09;、授权&#xff08;authorization&#xff09;和保护&#xff0c;以抵御常见攻击。对 常见漏洞 的保护提供了全面的支持&#xff0c;它对保护命令式和响应式应用程序有一流的支…

数据结构与算法效率分析:时间复杂度与空间复杂度详解(C语言)

1. 算法效率 1.1 如何衡量一个算法的好坏&#xff1f; 在计算机程序设计中&#xff0c;衡量算法优劣的核心标准是效率。但效率不仅指运行速度&#xff0c;还需要综合以下因素&#xff1a; 时间因素&#xff1a;算法执行所需时间 空间因素&#xff1a;算法运行占用的内存空间…

数据类设计_图片类设计之4_规则类图形混合算法(前端架构)

前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 接续上一篇,讨论图片类型设计出来后在场景中如何表达,以及图片的混合算法.前面的内容属于铺垫和基础,这篇内容和实际联系起来了. 背景图和前景图 这里笔者想先…

从零使用docker并安装部署mysql8.3.0容器

在开始使用docker到完成mysql的安装部署&#xff0c;中间有很多的坑等着 安装docker并配置 sudo yum install docker-ce 启动docker并设置开机启动项 sudo systemctl start docker sudo systemctl enable docker查看docker是否启动 sudo systemctl status docker 或者直接…

cpu 多级缓存L1、L2、L3 与主存关系

现代 CPU 的多级缓存&#xff08;L1、L2、L3&#xff09;和主存&#xff08;DRAM&#xff09;构成了一个层次化的内存系统&#xff0c;旨在通过减少内存访问延迟和提高数据访问速度来优化计算性能。以下是对多级缓存和主存的详细解析&#xff1a; 1. 缓存层次结构 现代 CPU 通…

基于Python+SQLite实现校园信息化统计平台

一、项目基本情况 概述 本项目以清华大学为预期用户&#xff0c;作为校内信息化统计平台进行服务&#xff0c;建立网页端和移动端校内信息化统计平台&#xff0c;基于Project_1的需求实现。 本项目能够满足校内学生团体的几类统计需求&#xff0c;如活动报名、实验室招募、多…

[多线程]基于阻塞队列(Blocking Queue)的生产消费者模型的实现

标题&#xff1a;[多线程]基于阻塞队列(Blocking Queue)的生产消费者模型的实现 水墨不写bug 文章目录 一、生产者消费者模型特点&#xff1a;二、实现2.1详细解释1. 成员变量2. 构造函数3. Isfull 和 Isempty4. Push 函数5. Pop 函数6. 析构函数7. GetSize 函数 三、总结与多线…

vue组件库el-menu导航菜单设置index,地址不会变更的问题

请先确认 1.路由已配置好 route-index.js如下&#xff0c; 2.view-ProHome.vue中已预留路由展示位 3.导航菜单复制组件库&#xff0c;并做修改 其中index与路由配置的地址一致 运行后发现点击菜单&#xff0c;url地址还是不变&#xff0c;查看组件库 Element - The worlds …

MySQL 优化方案

一、MySQL 查询过程 MySQL 查询过程是指从客户端发送 SQL 语句到 MySQL 服务器&#xff0c;再到服务器返回结果集的整个过程。这个过程涉及多个组件的协作&#xff0c;包括连接管理、查询解析、优化、执行和结果返回等。 1.1 查询过程的关键组件 连接管理器&#xff1a;管理…

智能对话小程序功能优化day1-登录鉴权

目录 1.数据库表构建。 2.完善登录相关的实例对象。 3.登录相关功能实现。 4.小程序效果。 最近尝试下trae加入claude3.7后的读图生成代码功能&#xff0c;可以看到简单的页面一次性生成确实准确率高了不少&#xff0c;想起来之前笔记中开发的智能问答小程序功能还是有些简…

MinIO的预签名直传机制

我们传统使用MinIo做OSS对象存储的应用方式往往都是在后端配置与MinIO的连接和文件上传下载的相关接口&#xff0c;然后我们在前端调用这些接口完成文件的上传下载机制&#xff0c;但是&#xff0c;当并发量过大&#xff0c;频繁访问会对后端的并发往往会对服务器造成极大的压力…

Qt开源控件库(qt-material-widgets)的编译及使用

项目简介 qt-material-widgets是一个基于 Qt 小部件的 Material Design 规范实现。 项目地址 项目地址&#xff1a;qt-material-widgets 本地构建环境 Win11 家庭中文版 VS2019 Qt5.15.2 (MSVC2019) 本地构建流程 克隆后的目录结构如图&#xff1a; 直接使用Qt Crea…

用python批量生成文件夹

问题描述 当批量生成文件夹时&#xff0c;手动右键创建文件夹是一个繁琐的过程&#xff0c;尤其是文件夹的命名过程。假设从3月10日到3月19日&#xff0c;每天要为某个日常工作创建一个名为2025031x的文件夹&#xff0c;手动创建文件夹并命名费时费力。 百度给出了以下四种方法…