Flutter 视频播放

在 Flutter 里官方提供了一个 video_player插件可以播放视频。

先安装依赖:

dependencies:
  video_player: ^0.6.4

基本使用

class _VideoAppState extends State<VideoApp> {
    VideoPlayerController _controller;
    bool _isPlaying = false;
    String url = 'http://vd3.bdstatic.com/mda-ifvq' +
                'u9yp3eaqueep/mda-ifvqu9yp3eaqueep.mp4';

    @override
    void initState() {
        super.initState();
        _controller = VideoPlayerController.network(this.url)
        // 播放状态
        ..addListener(() {
            final bool isPlaying = _controller.value.isPlaying;
            if (isPlaying != _isPlaying) {
                setState(() { _isPlaying = isPlaying; });
            }
        })
        // 在初始化完成后必须更新界面
        ..initialize().then((_) {
            setState(() {});
        });
    }

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Video Demo',
            home: new Scaffold(
                body: new Center(
                child: _controller.value.initialized
                    // 加载成功
                    ? new AspectRatio(
                        aspectRatio: _controller.value.aspectRatio,
                        child: VideoPlayer(_controller),
                    ) : new Container(),
                ),
                floatingActionButton: new FloatingActionButton(
                    onPressed: _controller.value.isPlaying
                        ? _controller.pause
                        : _controller.play,
                    child: new Icon(
                        _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
                    ),
                ),
            ),
        );
    }
}

下面是在模拟器下看到的效果(略卡)。


video_player 的 controller 有以下方法可用:

  • initialize() - 初始化播放器。
  • dispose() - 释放播放器资源。
  • notifyListeners() - 监听播放消息。
  • addListener(listener) - 添加监听器。
  • removeListener(listener) - 移除监听器。
  • pause() - 暂停播放。
  • play() - 开始播放。
  • position - 播放位置。
  • seekTo(moment) - 指定到某个位置播放。
  • setLooping(looping) - 是否循环播放。
  • setVolume(volume) - 设置音量大小。

使用 chewie

chewie,是一个非官方的第三方视频播放组件,看起来好像是基于 HTML5 播放的组件。chewie 相对 video_player 来说,有控制栏和全屏的功能。Chewie 使用 video_player 引擎并将其包裹在友好的 Material 或 Cupertino UI 中!
安装依赖:

dependencies
  chewie: ^0.6.1

基本使用:

import 'package:chewie/chewie.dart';

new Center(
    child: new Chewie(
        new VideoPlayerController.network(this.url),
        aspectRatio: 16 / 9,
        autoPlay: !true,
        looping: true,
        showControls: true,
        // 占位图
        placeholder: new Container(
            color: Colors.grey,
        ),

        // 是否在 UI 构建的时候就加载视频
        autoInitialize: !true,

        // 拖动条样式颜色
        materialProgressColors: new ChewieProgressColors(
            playedColor: Colors.red,
            handleColor: Colors.blue,
            backgroundColor: Colors.grey,
            bufferedColor: Colors.lightGreen,
        ),
    ),
),


chewie 实际上就是为 video_player 做了一个 UI 上的封装,因为 UI 实在长得太像。

控制栏样式?

chewie 并不能自定义控制栏样式,那只能自己修改源码了(修改的版本是 v0.6.1)。

首先打开文件:chewie/lib/src/material_controls.dart,在里面定义两个变量。

const lightColor = Color.fromRGBO(255, 255, 255, 0.85);
const darkColor = Color.fromRGBO(1, 1, 1, 0.35);
接着添加颜色值。

// 在 _buildExpandButton 下,大约 127 行
child: new Icon(
    widget.fullScreen ? Icons.fullscreen_exit : Icons.fullscreen,
    color: lightColor,
),

// 在 _buildHitArea 下,大约 157 行
decoration: new BoxDecoration(
    color: Colors.black54,
    borderRadius: new BorderRadius.circular(48.0),
),
// 167 行
child: new Icon(
    Icons.play_arrow,
    size: 32.0,
    color: lightColor,
),

// 在 _buildMuteButton 下,大约 206 行
child: new Icon(
    color: lightColor,
),

// 在 _buildPlayPause 下,大约 228 行
child: new Icon(
    controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
    color: lightColor,
),

// 在 _buildPosition 下,大约 244 行
style: new TextStyle(
    fontSize: 14.0,
    color: lightColor,
),

// 在 _buildProgressBar 下,尾行
new ChewieProgressColors(
    playedColor: lightColor,
    handleColor: lightColor,
    bufferedColor: Colors.white30,
    backgroundColor: darkColor,
),

此外 chewie 在全屏时没有一个退出全屏的返回按钮和标题显示,接着改。

// 在 build 里加一个 _buildHeader(),这个 header 需要自己定义。
@override
Widget build(BuildContext context) {
    return new Column(
        children: <Widget>[
            // 在全屏时才显示
            widget.fullScreen ? _buildHeader(context, _title) : new Container(),
            _buildHitArea(),
            _buildBottomBar(context, widget.controller),
        ],
    );
}

AnimatedOpacity _buildHeader(BuildContext context, String title) {
    return new AnimatedOpacity(
        opacity: _hideStuff ? 0.0 : 1.0,
        duration: new Duration(milliseconds: 300),
        child: new Container(
            color: darkColor,
            height: barHeight,
            child: new Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                    new IconButton(
                        onPressed: _onExpandCollapse,
                        color: lightColor,
                        icon: new Icon(Icons.chevron_left),
                    ),
                    new Text(
                        '$title',
                        style: new TextStyle(
                            color: lightColor,
                            fontSize: 18.0,
                        ),
                    ),
                ],
            ),
        ),
    );
}

标题是从上下文获取的,因此要一级一级的传递下去。

// chewie/lib/src/chewie_player.dart 文件

// 标题
final String title;

// 在构造函数处
this.title = '',

// 在 92 行左右,PlayerWithControls 构造的时候(有两个位置,两个都要加)
title: widget.title,

// chewie/lib/src/player_with_controls.dart 文件

// 标题
final String title;

// 在构造函数处
this.title = '',

// 在 92 行左右,MaterialControls 构造的时候
title: widget.title,

// chewie/lib/src/material_controls.dart
final String title;
@required this.title,
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_X自主阅读 15,969评论 3 119
  • 想你的时候 真的是要哭出来了呢 我什么时候 才可以云淡风轻的说一句 啊 又想起你了
    十八只鱼阅读 297评论 5 4
  • 今天一哥们给我打电话说自己要装监控,我问他要几个,他说,十来个吧。我的大兄弟,在哪发了横财,买了什么豪宅啊,要这么...
    暖心晴子阅读 245评论 0 0
  • 年轻时总想着有机会能乘坐飞机旅行一次,想象着那是一种多么高端、大气、上档次的人生体验。 97年的春天,机会终于来了...
    清浅墨客阅读 283评论 0 1