Flutter视频播放主题定制插件video_js_themed的使用
Flutter视频播放主题定制插件video_js_themed的使用
Flutter 插件 video_js_themed
用于在 Flutter Web 应用中集成 Video.js 播放器,并支持主题定制。
安装
将插件添加到项目的 pubspec.yaml
文件中:
dependencies:
video_js_themed: ^0.0.1
Web 配置
在 Web 部分的 index.html
文件中包含 Video.js 和主题库:
<link href="https://unpkg.com/video.js@7.20.2/dist/video-js.min.css" rel="stylesheet">
<link href="https://unpkg.com/@videojs/themes@1/dist/fantasy/index.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@7.20.2/dist/video.min.js"></script>
示例代码
以下是一个完整的示例代码,展示了如何使用 video_js_themed
插件来创建一个带有主题的视频播放器。
import 'package:flutter/material.dart';
import 'package:videojs_themed/videojs.dart';
void main() {
// 初始化 JavaScript 回调
VideoJsResults().init();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Video JS with Theme Demo',
home: const OptionsPage(),
);
}
}
class OptionsPage extends StatefulWidget {
const OptionsPage({Key? key}) : super(key: key);
[@override](/user/override)
OptionsPageState createState() => OptionsPageState();
}
class OptionsPageState extends State<OptionsPage> {
bool? controls = true;
bool? loop = false;
bool? muted = false;
String? aspectRatio = '16:9';
bool? fluid = false;
bool? fill = false;
String? language = 'en';
bool? liveUI = false;
String? notSupportedMessage = 'this movie type not supported';
String? source = 'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8';
String? sourceType = 'application/x-mpegURL';
List<double>? playbackRates = [];
bool? preferFullWindow = false;
bool? responsive = false;
bool? suppressNotSupportedError = false;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('videoJs Options'),
),
body: ListView(
children: [
CheckboxListTile(
title: const Text('Controls'),
value: controls,
onChanged: (val) {
setState(() {
controls = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Loop'),
value: loop,
onChanged: (val) {
setState(() {
loop = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Muted'),
value: muted,
onChanged: (val) {
setState(() {
muted = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Fluid'),
value: fluid ?? false,
onChanged: (val) {
setState(() {
fluid = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Fill'),
value: fill ?? false,
onChanged: (val) {
setState(() {
fill = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Live UI'),
value: liveUI ?? false,
onChanged: (val) {
setState(() {
liveUI = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Prefer Full Window'),
value: preferFullWindow ?? false,
onChanged: (val) {
setState(() {
preferFullWindow = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Responsive'),
value: responsive ?? false,
onChanged: (val) {
setState(() {
responsive = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
CheckboxListTile(
title: const Text('Suppress Not Supported Error'),
value: suppressNotSupportedError,
onChanged: (val) {
setState(() {
suppressNotSupportedError = val;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
ListTile(
leading: const Text('Aspect Ratio'),
title: TextField(
controller: TextEditingController(text: aspectRatio ?? '16:9'),
onChanged: (val) {
aspectRatio = val;
},
),
),
ListTile(
leading: const Text('Language'),
title: TextField(
controller: TextEditingController(text: language),
onChanged: (val) {
language = val;
},
),
),
ListTile(
leading: const Text('Not Supported Message'),
title: TextField(
controller: TextEditingController(text: notSupportedMessage),
onChanged: (val) {
notSupportedMessage = val;
},
),
),
ListTile(
leading: const Text('Source'),
title: TextField(
controller: TextEditingController(text: source),
onChanged: (val) {
source = val;
},
),
),
ListTile(
leading: const Text('Source Type'),
title: TextField(
controller: TextEditingController(text: sourceType),
onChanged: (val) {
sourceType = val;
},
),
),
ListTile(
leading: const Text('Playback Rates'),
title: TextField(
controller: TextEditingController(text: '1,2,3'),
onChanged: (val) {
playbackRates!.clear();
val.split(',').forEach((element) {
if (element != '') {
playbackRates!.add(double.parse(element));
}
});
},
),
),
const SizedBox(height: 30),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyHomePage(
videoJsOptions: VideoJsOptions(
controls: controls,
loop: loop,
muted: muted,
aspectRatio: aspectRatio,
fluid: fluid,
fill: fill,
language: language,
liveui: liveUI,
notSupportedMessage: notSupportedMessage,
playbackRates: playbackRates,
preferFullWindow: preferFullWindow,
responsive: responsive,
sources: [Source(source!, sourceType!)],
suppressNotSupportedError: suppressNotSupportedError,
),
),
),
);
},
child: const Text(
'Navigate to video page',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(height: 30),
],
),
);
}
}
class MyHomePage extends StatefulWidget {
final VideoJsOptions videoJsOptions;
const MyHomePage({Key? key, required this.videoJsOptions}) : super(key: key);
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String playerId = 'videoId';
TextEditingController videoSourceController = TextEditingController();
TextEditingController videoTypeController = TextEditingController();
late VideoJsController videoJsController;
[@override](/user/override)
void initState() {
super.initState();
videoSourceController.text = 'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8';
videoTypeController.text = 'application/x-mpegURL';
videoJsController = VideoJsController(
playerId,
videoJsOptions: widget.videoJsOptions,
qualitySelector: true,
);
}
[@override](/user/override)
void dispose() {
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('videojs with theme example'),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
VideoJsWidget(
videoJsController: videoJsController,
height: MediaQuery.of(context).size.width / 2.5,
width: MediaQuery.of(context).size.width / 1.5,
theme: 'vjs-theme-fantasy',
)
],
),
const SizedBox(height: 100),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 200,
height: 50,
child: TextField(
controller: videoSourceController,
decoration: const InputDecoration(hintText: 'video'),
),
),
const SizedBox(width: 10),
SizedBox(
width: 100,
height: 50,
child: TextField(
controller: videoTypeController,
decoration: const InputDecoration(hintText: 'type'),
),
),
const SizedBox(width: 15),
ElevatedButton(
onPressed: () {
videoJsController.setSRC(
videoSourceController.text.toString(),
type: videoTypeController.text.toString(),
);
},
child: const Text(
'Set source',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 50),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.dispose();
},
child: const Text(
'Dispose',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.play();
},
child: const Text(
'Play',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.pause();
},
child: const Text(
'Pause',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.isPaused((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Pause status : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Is pause',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.currentTime((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Current video time : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Current video time',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.getVolume((val) =>
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Volume is : $val',
style: const TextStyle(color: Colors.white),
),
)));
},
child: const Text(
'Get volume',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.setVolume('0.5');
},
child: const Text(
'Set volume to 0.5',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.toggleMute();
},
child: const Text(
'Toggle mute',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.isMute((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Mute status : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Mute status',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.toggleFullScreen();
},
child: const Text(
'Toggle full screen',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.isFullScreen((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Full screen status : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Full screen status',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.requestFullScreen();
},
child: const Text(
'Request full screen',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.exitFullScreen();
},
child: const Text(
'Exit full screen',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.setCurrentTime('100');
},
child: const Text(
'Set video time to 100 sec',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.durationTime((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Duration time : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Duration',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.remainTime((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Remain time : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Remain time',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.bufferPercent((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Buffer percent : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Buffer percent',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
videoJsController.setPoster(
'https://file-examples-com.github.io/uploads/2017/10/file_example_JPG_100kB.jpg',
);
},
child: const Text(
'Set video poster',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: () {
videoJsController.getPoster((val) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(milliseconds: 500),
content: Text(
'Video poster : $val',
style: const TextStyle(color: Colors.white),
),
));
});
},
child: const Text(
'Get video poster',
style: TextStyle(color: Colors.white),
),
),
],
),
const SizedBox(height: 50),
],
),
),
),
);
}
}
更多关于Flutter视频播放主题定制插件video_js_themed的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频播放主题定制插件video_js_themed的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
video_js_themed
是一个 Flutter 插件,用于在应用中播放视频,并提供了主题定制的功能。它基于 video_player
插件,并添加了对主题的自定义支持,使开发者能够更容易地调整视频播放器的外观和感觉。
安装插件
首先,你需要在 pubspec.yaml
文件中添加 video_js_themed
插件的依赖:
dependencies:
flutter:
sdk: flutter
video_js_themed: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装插件。
基本用法
-
导入插件
在你的 Dart 文件中导入
video_js_themed
插件:import 'package:video_js_themed/video_js_themed.dart';
-
创建 VideoPlayerController
你需要创建一个
VideoPlayerController
来控制视频的播放。你可以从网络、本地文件或资产中加载视频。final VideoPlayerController controller = VideoPlayerController.network( 'https://www.example.com/sample.mp4', );
-
初始化控制器
在播放视频之前,你需要初始化控制器:
await controller.initialize();
-
使用 VideoJsThemed 组件
使用
VideoJsThemed
组件来显示视频播放器,并应用自定义主题:VideoJsThemed( controller: controller, theme: VideoTheme( playButtonColor: Colors.blue, progressBarColor: Colors.red, // 其他主题属性 ), )
自定义主题
VideoJsThemed
提供了多种主题属性,允许你自定义视频播放器的外观。以下是一些常用的主题属性:
playButtonColor
: 播放按钮的颜色。progressBarColor
: 进度条的颜色。backgroundColor
: 播放器的背景颜色。textColor
: 文本颜色(如时间显示)。controlBarColor
: 控制条的颜色。fullscreenButtonColor
: 全屏按钮的颜色。
你可以根据需要调整这些属性来创建符合你应用风格的主题。
控制视频播放
你可以通过 VideoPlayerController
来控制视频的播放、暂停、停止等操作:
controller.play(); // 播放视频
controller.pause(); // 暂停视频
controller.seekTo(Duration(seconds: 10)); // 跳转到指定时间
示例代码
以下是一个完整的示例代码,展示了如何使用 video_js_themed
插件来播放视频并应用自定义主题:
import 'package:flutter/material.dart';
import 'package:video_js_themed/video_js_themed.dart';
import 'package:video_player/video_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Video.js Themed Example',
home: VideoPlayerScreen(),
);
}
}
class VideoPlayerScreen extends StatefulWidget {
[@override](/user/override)
_VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
late VideoPlayerController _controller;
[@override](/user/override)
void initState() {
super.initState();
_controller = VideoPlayerController.network(
'https://www.example.com/sample.mp4',
)..initialize().then((_) {
setState(() {});
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Video.js Themed Example'),
),
body: Center(
child: _controller.value.isInitialized
? VideoJsThemed(
controller: _controller,
theme: VideoTheme(
playButtonColor: Colors.blue,
progressBarColor: Colors.red,
backgroundColor: Colors.black,
textColor: Colors.white,
controlBarColor: Colors.grey[800]!,
fullscreenButtonColor: Colors.white,
),
)
: CircularProgressIndicator(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
[@override](/user/override)
void dispose() {
super.dispose();
_controller.dispose();
}
}