咱們每每寫項目都是着急上手,總想着先寫後面有時間了再(說)來(的)優(好)化(聽),這樣寫出來的代碼每每都是跟業務系統耦合在一塊要麼就是質量不高,下次使用的時候就想重構,有人說項目急沒辦法(曾經我也這麼說過),可是一個好的編程習慣真的能夠作到事半功倍。既然是一種習慣,那麼確定是能夠改的,首先我要先習慣利用思惟導圖來明確明白本身要什麼,有什麼功能,開始設計接口以及參數,最後纔是分優先級而後根據優先級來執行下一步該作什麼,這樣能夠很大高效的避免踩坑,避免由於設計不合理須要重構就麻煩了。閒話很少說下面進入正題。git
那麼什麼叫高度自由的播放器呢?我是這麼認爲的:首先儘量的開放權限來更改配置,其次模塊化設計,同時還須要跟業務代碼解耦,光有這些還不算夠,最後咱們須要讓視頻播放器實現自定義拓展,也就是說現有播放器功能知足不了本身需求的時候,開發者能夠本身動手,例如視頻的字幕
,彈幕
,視頻頂部控制欄
等。github
經過上圖咱們能夠看一下播放器都有哪些屬性呢?編程
播放器屬性:數組
屬性 | 類型 | 描述 |
---|---|---|
dataSource | String | 視頻URL或媒體文件的路徑 |
children | List | 自定義拓展的子元素,須要使用 WidgetAlign (字幕、彈幕、視頻頂部控制欄等) |
onplay | VideoCallback | 視頻開始播放的回調 |
onpause | VideoCallback | 視頻暫停播放回調 |
ontimeupdate | VideoCallback | 視頻播放進度回調(經過返回的value進行字幕匹配) |
onend | VideoCallback | 視頻播放結束回調 |
playOptions | VideoPlayOptions | 視頻播放自定義配置(詳情見下方的Useage) |
videoStyle | VideoStyle | 視頻播放器自定義樣式(詳情見下方的Useage) |
播放器自定義配置 (VideoPlayOptions):緩存
屬性 | 類型 | 描述 |
---|---|---|
startPosition | Duration | 開始播放節點,例如:Duration(seconds: 0)) |
loop | bool | 是否循環播放 |
seekSeconds | num | 設置視頻快進/快退單位秒數 |
autoplay | bool | 是否自動播放 |
aspectRatio | num | 視頻播放比例,例如:16/9 或者 4/3 |
allowScrubbing | bool | 是否運行進度條拖拽 |
播放器自定義樣式 (VideoStyle):bash
屬性 | 類型 | 描述 |
---|---|---|
playIcon | Widget | 視頻暫停播放時中央顯示的圖標,showPlayIcon爲false 時,該屬性設置無效。 |
showPlayIcon | bool | 暫停時是否顯示播放按鈕 |
videoControlBarStyle | VideoControlBarStyle | 控制欄自定義樣式 |
videoSubtitlesStyle | VideoSubtitles | 字幕自定義樣式 |
控制欄自定義樣式 (VideoControlBarStyle):微信
屬性 | 類型 | 描述 |
---|---|---|
barBackgroundColor | Color | 控制欄背景顏色,默認爲Color.fromRGBO(0, 0, 0, 0.5) |
playedColor | Color | 已播放的進度條顏色(下圖1 詳細說明) |
bufferedColor | Color | 已緩衝的進度條顏色(下圖1 詳細說明) |
backgroundColor | Color | 進度條背景顏色(下圖1 詳細說明) |
playIcon | Widget | 控制欄播放圖標(下圖2 詳細說明) |
pauseIcon | Widget | 控制欄暫停圖標(下圖2 詳細說明) |
rewindIcon | Widget | 控制欄快退圖標(下圖2 詳細說明) |
forwardIcon | Widget | 控制欄快進圖標(下圖2 詳細說明) |
fullscreenIcon | Widget | 控制欄全屏圖標(下圖2 詳細說明) |
fullscreenExitIcon | Widget | 控制欄取消全屏圖標(下圖2 詳細說明) |
itemList | List | 控制欄自定義功能(下圖3 詳細說明),默認爲["rewind", "play", "forward", "progress", "time", "fullscreen"]。若是咱們須要調整控制欄顯示的順序,僅須要調整 list 中字符串的順序,若是須要刪減,直接從 list 中移除改字符串便可,例如移除快進和快退,則講 list 設置爲 ["play", "progress", "time", "fullscreen"] 便可。後面會陸續開放自定義元素,也就是你把你的元素加入到 list 中。 |
添加依賴,打開根目錄的pubspec.yaml
文件,在dependencies:
下面添加如下代碼app
awsome_video_player: #latest
複製代碼
安裝依賴(若是已經自動安裝請忽略)ide
cd 項目目錄
flutter packages get
複製代碼
在頁面中引入庫模塊化
import 'package:awsome_video_player/awsome_video_player.dart';
複製代碼
這是一個完整的
main.dart
import 'package:flutter/material.dart';
import 'package:awsome_video_player/awsome_video_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String mainSubtitles = "主字幕";
String subSubtitles = "輔字幕";
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Awsome video player'),
),
body: Center(
child: AwsomeVideoPlayer(
"https://www.runoob.com/try/demo_source/movie.mp4",
/// 視頻播放配置
playOptions: VideoPlayOptions(
seekSeconds: 30,
aspectRatio: 16 / 9,
loop: true,
autoplay: true,
allowScrubbing: true,
startPosition: Duration(seconds: 0)),
/// 自定義視頻樣式
videoStyle: VideoStyle(
/// 自定義視頻暫停時視頻中部的播放按鈕
playIcon: Icon(
Icons.play_circle_outline,
size: 100,
color: Colors.white,
),
/// 暫停時是否顯示視頻中部播放按鈕
showPlayIcon: true,
/// 自定義底部控制欄
videoControlBarStyle: VideoControlBarStyle(
/// 自定義顏色
//playedColor: Colors.red,
//bufferedColor: Colors.yellow,
//backgroundColor: Colors.green,
//barBackgroundColor: Colors.blue,
/// 更改進度欄的播放按鈕
playIcon: Icon(
Icons.play_arrow,
color: Colors.white,
size: 16
),
/// 更改進度欄的暫停按鈕
pauseIcon: Icon(
Icons.pause,
color: Colors.red,
size: 16,
),
/// 更改進度欄的快退按鈕
rewindIcon: Icon(
Icons.replay_30,
size: 16,
color: Colors.white,
),
/// 更改進度欄的快進按鈕
forwardIcon: Icon(
Icons.forward_30,
size: 16,
color: Colors.white,
),
/// 更改進度欄的全屏按鈕
fullscreenIcon: Icon(
Icons.fullscreen,
size: 16,
color: Colors.white,
),
/// 更改進度欄的退出全屏按鈕
fullscreenExitIcon: Icon(
Icons.fullscreen_exit,
size: 16,
color: Colors.red,
),
/// 決定控制欄的元素以及排序,示例見上方圖3
itemList: [
"rewind",
"play",
"forward",
"progress",
"time",
"fullscreen"
],
),
/// 自定義字幕
videoSubtitlesStyle: VideoSubtitles(
mianTitle: Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.fromLTRB(10, 0, 10, 30),
child: Text(
mainSubtitles,
maxLines: 2,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white, fontSize: 14)),
),
),
subTitle: Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.all(10),
child: Text(
subSubtitles,
maxLines: 2,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white, fontSize: 14)),
),
),
),
),
/// 自定義拓展元素
children: [
/// 添加自定義視頻頂部返回按鈕
Align(
alignment: Alignment.topLeft,
child: GestureDetector(
onTap: () {
print("This is test from children.");
},
child: Container(
margin: EdgeInsets.only(top: 5, left: 5),
width: 30,
height: 30,
decoration: BoxDecoration(
color: Color.fromRGBO(0, 0, 0, .5),
borderRadius: BorderRadius.all(Radius.circular(15)),
),
child: Icon(Icons.arrow_back, size: 16, color: Colors.white,)
),
),
),
/// 這個將會覆蓋的視頻內容,由於這個層級是最高級,所以手勢會失效(慎用)
/// 這個能夠用來作視頻廣告
// Positioned(
// top: 0,
// left: 0,
// bottom: 0,
// right: 0,
// child: Text("data", style: TextStyle(color: Colors.white),),
// ),
],
/// 視頻暫停回調
onpause: (value) {
print("video paused");
},
/// 視頻播放回調
onplay: (value) {
print("video played");
},
/// 視頻播放結束回調
onended: (value) {
print("video ended");
},
/// 視頻播放進度回調
/// 能夠用來匹配字幕
ontimeupdate: (value) {
print("timeupdate ${value}");
var position = value.position.inMilliseconds / 1000;
//根據 position 來判斷當前顯示的字幕
},
),
),
),
);
}
}
複製代碼
首先我來看一下控制欄的圖標自定義(見上圖2):
DEMO: main.dart
import 'package:flutter/material.dart';
import 'package:awsome_video_player/awsome_video_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Awsome video player'),
),
body: Center(
child: AwsomeVideoPlayer(
"https://www.runoob.com/try/demo_source/movie.mp4",
/// 視頻播放配置
playOptions: VideoPlayOptions(
seekSeconds: 30,
aspectRatio: 16 / 9,
loop: true,
autoplay: true,
allowScrubbing: true,
startPosition: Duration(seconds: 0)),
/// 自定義視頻樣式 - 請注意我要劃重點了
videoStyle: VideoStyle(
/// 自定義底部控制欄 - 這是重點了
videoControlBarStyle: VideoControlBarStyle(
/// 更改進度欄的播放按鈕
playIcon: Icon(
Icons.play_arrow,
color: Colors.white,
size: 16
),
/// 更改進度欄的暫停按鈕
pauseIcon: Icon(
Icons.pause,
color: Colors.red,
size: 16,
),
/// 更改進度欄的快退按鈕
rewindIcon: Icon(
Icons.replay_30,
size: 16,
color: Colors.white,
),
/// 更改進度欄的快進按鈕
forwardIcon: Icon(
Icons.forward_30,
size: 16,
color: Colors.white,
),
/// 更改進度欄的全屏按鈕
fullscreenIcon: Icon(
Icons.fullscreen,
size: 16,
color: Colors.white,
),
/// 更改進度欄的退出全屏按鈕
fullscreenExitIcon: Icon(
Icons.fullscreen_exit,
size: 16,
color: Colors.red,
),
),
),
),
),
),
);
}
}
複製代碼
咱們能夠根據videoStyle
中videoControlBarStyle
來自定義控制欄的樣式:調整順序(見上方圖3)只須要調整 itemList
中字符串的順序便可;控制顯示的元素,將不須要暫時的元素從 itemList
中刪除便可。
DEMO: main.dart
import 'package:flutter/material.dart';
import 'package:awsome_video_player/awsome_video_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Awsome video player'),
),
body: Center(
child: AwsomeVideoPlayer(
"https://www.runoob.com/try/demo_source/movie.mp4",
/// 視頻播放配置
playOptions: VideoPlayOptions(
seekSeconds: 30,
aspectRatio: 16 / 9,
loop: true,
autoplay: true,
allowScrubbing: true,
startPosition: Duration(seconds: 0)),
/// 自定義視頻樣式 - 請注意我要劃重點了
videoStyle: VideoStyle(
/// 自定義底部控制欄 - 這是重點了
videoControlBarStyle: VideoControlBarStyle(
/// 決定控制欄的元素以及排序,示例見上方圖3
itemList: [
"progress",// 這裏將進度條前置了,所以有了圖3的效果
"rewind",//若是須要刪除快退按鈕,將其註釋或刪除便可
"play",
"forward",
"time",
"fullscreen"
],
),
),
),
),
),
);
}
}
複製代碼
一樣咱們仍是經過videoStyle
中videoControlBarStyle
來自定義進度條的顏色(見上方圖3)。
DEMO: main.dart
import 'package:flutter/material.dart';
import 'package:awsome_video_player/awsome_video_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Awsome video player'),
),
body: Center(
child: AwsomeVideoPlayer(
"https://www.runoob.com/try/demo_source/movie.mp4",
/// 視頻播放配置
playOptions: VideoPlayOptions(
seekSeconds: 30,
aspectRatio: 16 / 9,
loop: true,
autoplay: true,
allowScrubbing: true,
startPosition: Duration(seconds: 0)),
/// 自定義視頻樣式
videoStyle: VideoStyle(
/// 自定義底部控制欄
videoControlBarStyle: VideoControlBarStyle(
/// 自定義顏色
playedColor: Colors.red,//已播放進度條的顏色
bufferedColor: Colors.yellow,//已緩存進度條的顏色
backgroundColor: Colors.green,//進度條的背景顏色
barBackgroundColor: Colors.blue,//控制欄的背景顏色
),
),
),
),
),
);
}
}
複製代碼
視頻若是須要橫豎屏不能使用safeArea
視頻的 dataSoure
不能爲空,爲空時使用加載視圖,不然播放器會報錯
import 'package:flutter/material.dart';
import 'package:awsome_video_player/awsome_video_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String videoUrl = "https://www.runoob.com/try/demo_source/movie.mp4";
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Awsome video player'),
),
body: Center(
/// 通常videoUrl是從服務端返回,在沒有返回來以前,
/// 咱們可使用加載視圖來佔位
child: videoUrl != "" ? AwsomeVideoPlayer(
videoUrl,
/// 視頻播放配置
playOptions: VideoPlayOptions(
seekSeconds: 30,
aspectRatio: 16 / 9,
loop: true,
autoplay: true,
allowScrubbing: true,
startPosition: Duration(seconds: 0)),
) : AspectRatio(
aspectRatio: 16 / 9,
child: Center(
child: CircularProgressIndicator(strokeWidth: 2.0),
),
),
),
),
);
}
}
複製代碼
AwsomeVideoPlayer
下面的children
僅支持Align
和Positioned
,children的層級會高於下面,這個功能會持續更新,後面會陸續出一些針對自定義拓展的高階文檔。
開發過程當中遇到問題,請經過如下方式聯繫我,我會第一時間回覆你:
Copyright © 2020, Mark Chen. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 「Software」), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 「AS IS」, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.