Flutter视频播放器插件
迪鲁宾 人气:0您已经看到很多包含视频内容的应用程序,比如带有视频教程的食谱应用程序、电影应用程序和体育相关的应用程序。您是否想知道如何将视频内容添加到您的下一个Flutter应用程序中?
从头开始实现视频功能将是一项繁重的任务。但有几个插件可以让开发者的生活变得轻松。视频播放器插件是可用于 Flutter 的最佳插件之一,可满足这一要求。
在这篇文章中,您将学习如何应用视频播放器插件以及控制视频播放器的不同功能。
我们将讨论这些主题。
- 创建一个新的视频播放器
- 添加播放和暂停按钮
- 创建一个快进
- 添加一个视频进度指示器
- 应用视频的字幕
创建一个新的视频播放器
在使用视频播放器插件之前,你应该把它添加到你的pubspec.yaml
文件中。当你打开pubspec.yaml
文件时,你可以看到运行你的应用程序所需的一些配置和依赖性。我们的视频播放器插件应该被添加到dependencies
块下。
dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 video_player: 2.1.15 //video player
该插件的当前版本是2.1.15
,但你可以通过查看插件页面在这里添加最新版本。如果你保存文件时是在VS Code中,它会自动下载该插件。如果不是,打开终端,写flutter pub get
来下载该插件。
进入你想添加该插件的文件,并导入video_player.dart
文件。
import 'package:video_player/video_player.dart';
现在你可以在你的项目中使用视频播放器插件了。
有几种方法来加载视频。让我们从资产中加载我们的例子。在项目的根层创建一个assets/video文件夹,在该文件夹内添加一个视频。然后在pubspec.yaml
,在assets
部分,指定文件路径,如下所示。
assets: - assets/video/video.mp4
让我们创建一个单独的有状态的部件,称为VideoPlayerWidget
,以插入我们的视频播放器相关的实现。
你可以在initState
方法中初始化视频播放器,如下所示。另外,别忘了dispose
,让视频播放器做清理工作。
class _VideoPlayerState extends State<VideoPlayerWidget> { late VideoPlayerController _videoPlayerController; @override void initState() { super.initState(); _videoPlayerController = VideoPlayerController.asset( 'assets/video/video.mp4') ..initialize().then((_) { setState(() {}); _videoPlayerController.play(); }); } @override void dispose() { _videoPlayerController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Center( child: VideoPlayer(_videoPlayerController), ); } }
VideoPlayerController
必须用late
关键字来指定,因为我们在这一行中仍然没有定义视频播放器控制器,我们将在后面做这个。在initState
里面,videoPlayerController
已经和资产的路径一起被初始化。
当初始化完成后,它改变了状态并重建了小部件。你可以在初始化后开始播放视频。
取代assets
,你可以使用视频的URL。为了访问网络,你应该给Android和iOS添加互联网权限配置。
从根目录下,进入ios/Runner
,打开info.plist
文件。然后,在该文件中添加以下配置。
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
接下来,去android/app/src/main
,并打开AndroidManifest.xml
。然后,向其添加以下代码。
<uses-permission android:name="android.permission.INTERNET"/>
现在你可以把asset
改为network
,并在那里添加视频URL。
@override void initState() { super.initState(); _videoPlayerController = VideoPlayerController.network('video_url_here') ..initialize().then((_) { setState(() {}); _videoPlayerController.play(); }); }
即使初始化已经完成,也应该有办法在用户界面中显示播放器。VideoPlayer
widget可以用来做到这一点。为了使它工作,你应该把控制器作为第一个参数传递给VideoPlayer
widget。
在显示VideoPlayer
widget之前,最好先检查初始化是否成功。
@override Widget build(BuildContext context) { return Center( child: _videoPlayerController.value.isInitialized ? VideoPlayer(_videoPlayerController) : Container(), ); }
现在你可以看到屏幕上的视频了。但是有一个小问题:它的长宽比不合适。这可以通过使用AspectRatio
widget来解决。视频播放器提供了一个适当的视频长宽比,你可以使用这个值来设置为AspectRatio
widget。
@override Widget build(BuildContext context) { return Center( child: _videoPlayerController.value.isInitialized ? AspectRatio(aspectRatio: _videoPlayerController.value.aspectRatio, child: VideoPlayer(_videoPlayerController) ) : Container(), ); }
现在你可以看到具有适当长宽比的视频。
添加播放和暂停按钮
首先,让我们把视频播放器小部件包在一个列小部件里面,因为我们应该把播放和暂停按钮放在播放器下面。在播放器小组件之后的列内,让我们在一个Row
小组件内添加两个ElevatedButton
小组件,在这些按钮之间让我们添加一个Padding
小组件以保持一些呼吸空间。
对每个ElevatedButton
,添加相关的Icons
,作为子部件。然后在播放按钮onPressed
的回调里面,你可以参考_videoPlayerController
,并调用play
方法来开始播放视频。在暂停按钮里面,使用pause
方法而不是播放。
现在你可以删除之前在initState
方法里面添加的播放。
@override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _videoPlayerController.value.isInitialized ? AspectRatio(aspectRatio: _videoPlayerController.value.aspectRatio, child: VideoPlayer(_videoPlayerController) ) : Container(), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton(onPressed: (){ _videoPlayerController.pause(); }, child: Icon(Icons.pause)), Padding(padding: EdgeInsets.all(2)), ElevatedButton(onPressed: (){ _videoPlayerController.play(); }, child: Icon(Icons.play_arrow)) ], ) ], ); }
另外,你可以给按钮添加样式,得到一个看起来很圆的按钮,这通常是在视频播放器中。
@override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _videoPlayerController.value.isInitialized ? AspectRatio( aspectRatio: _videoPlayerController.value.aspectRatio, child: VideoPlayer(_videoPlayerController)) : Container(), Padding( padding: EdgeInsets.all(20), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all<Color>(Colors.blue), fixedSize: MaterialStateProperty.all(Size(70, 70)), shape: MaterialStateProperty.all(RoundedRectangleBorder( borderRadius: BorderRadius.circular(100)))), onPressed: () { _videoPlayerController.pause(); }, child: Icon(Icons.pause)), Padding(padding: EdgeInsets.all(2)), ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all<Color>(Colors.redAccent), fixedSize: MaterialStateProperty.all<Size>(Size(80, 80)), shape: MaterialStateProperty.all(RoundedRectangleBorder( borderRadius: BorderRadius.circular(100)))), onPressed: () { _videoPlayerController.play(); }, child: Icon(Icons.play_arrow)) ], ) ], ); }
创建一个快进
在实现快进之前,让我们思考一下我们需要什么。首先,应该有一个访问当前视频位置/时间的方法和一个设置新值的方法。控制器的seekTo
方法允许我们为视频设置持续时间。
你可以通过视频播放器value
属性访问当前的视频位置,就像下面这样。
ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all<Color>(Colors.blue), fixedSize: MaterialStateProperty.all(Size(70, 70)), shape: MaterialStateProperty.all(RoundedRectangleBorder( borderRadius: BorderRadius.circular(100)))), onPressed: () { _videoPlayerController.seekTo(Duration( seconds: _videoPlayerController.value.position.inSeconds + 10)); }, child: Icon(Icons.fast_forward))
像这样,当用户点击按钮时,你也可以通过减少10
秒来实现向后倒转。
添加一个视频进度指示器
视频播放器插件提供了内置的功能来添加一个进度条以及一些控件。你可以使用VideoProgressIndicator
widget来实现这个功能。
作为第一个参数,你必须传递控制器并设置allowScrubbing
属性。allowScrubbing
属性将允许用户通过触摸小组件来滑动进度。通过启用这个,用户可以跳到视频的不同时间戳。此外,你还可以单独控制寻求栏的背景颜色、缓冲区颜色和播放区颜色。
VideoProgressIndicator( _videoPlayerController, allowScrubbing: true, colors: VideoProgressColors( backgroundColor: Colors.red, bufferedColor: Colors.black, playedColor: Colors.blueAccent), )
应用视频的字幕
字幕对你的应用程序来说需要两样东西。第一个是不同时期的段落/单词列表,第二个是在视频播放时显示这些标题的方法。为此,应该有一种方法来为时间变化添加一个监听器。
视频播放器包含一个addListener
方法,每秒钟执行一次。你可以使用这个监听器,根据不同的时间段为视频播放器提供字幕。
首先,让我们创建一个Map
,其中包含时间作为一个键,字幕文本作为一个值。在Map
,时间的单位将是秒。
Map<int,String> captions = { 5:"First subtitle", 20:"Second subtitle" };
接下来,在初始化视频播放器时注册一个Listener
。在回调里面,你可以检查视频是否正在播放,如果视频正在播放,则获得当前的时间为秒。然后,如果当前值包含在captions
地图中,我们可以像下面这样将该值设置为选定的标题。
void initState() { super.initState(); _videoPlayerController = VideoPlayerController.asset('assets/video/video.mp4') ..addListener(() { if(_videoPlayerController.value.isPlaying){ setState(() { if(captions.containsKey(_videoPlayerController.value.position.inSeconds)){ selectedCaption = captions[_videoPlayerController.value.position.inSeconds]; } }); } }) ..initialize().then((_) { setState(() {}); _videoPlayerController.play(); }); }
现在你可以使用ClosedCaption
来设置那个选定的标题。你可以给标题文本添加一些样式,以获得更好的可见性。
ClosedCaption( text: selectedCaption,textStyle: TextStyle(fontSize: 15,color: Colors.white),)
但是,每次标题改变时,建立主部件并不是好的做法。因此,我们应该把标题逻辑提取到一个单独的小部件。
要注册一个监听器,你应该把视频控制器传递给一个新创建的子部件。
从那里,你可以在子部件内注册监听器。
class VCaption extends StatefulWidget { const VCaption( this.videoPlayerController, ); final VideoPlayerController videoPlayerController; @override _VCaptionState createState() => _VCaptionState(); } class _VCaptionState extends State<VCaption> { String? selectedCaption = ""; Map<int,String> captions = { 5:"First subtitle", 20:"Second subtitle" }; @override void initState() { widget.videoPlayerController.addListener(() { if(widget.videoPlayerController.value.isPlaying){ print("Time ${widget.videoPlayerController.value.position.inSeconds}"); setState(() { if(captions.containsKey(widget.videoPlayerController.value.position.inSeconds)){ selectedCaption = captions[widget.videoPlayerController.value.position.inSeconds]; } }); } }); super.initState(); } @override Widget build(BuildContext context) { return ClosedCaption( text: selectedCaption,textStyle: TextStyle(fontSize: 15,color: Colors.white),); } }
现在我们可以在之前创建的栏目内添加这个小部件,并将_videoPlayerController
作为参数传递。你可以在把小部件添加到树上之前检查视频播放器是否已经被初始化,就像下面这样。
_videoPlayerController.value.isInitialized ? VCaption(_videoPlayerController) : Container(),
你可以使用Stack
widget在视频顶部显示这些字幕,而不是在视频下面显示那些字幕。字幕以及进度指示器已经被移到了Stack
widget里面,以便在视频的顶部显示。
Stack( children: [ _videoPlayerController.value.isInitialized ? AspectRatio( aspectRatio: _videoPlayerController.value.aspectRatio, child: VideoPlayer(_videoPlayerController)) : Container(), Positioned( bottom: 2, width: MediaQuery.of(context).size.width, child: _videoPlayerController.value.isInitialized ? VCaption(_videoPlayerController) : Container(), ), Positioned( bottom: 0, width: MediaQuery.of(context).size.width, child: VideoProgressIndicator( _videoPlayerController, allowScrubbing: false, colors: VideoProgressColors( backgroundColor: Colors.blueGrey, bufferedColor: Colors.blueGrey, playedColor: Colors.blueAccent), )) ], )
结论
使用视频播放器插件而不是从头开始实现一个视频播放器,可以节省大量的开发时间,并提供所有开箱即用的功能。
如果您想超越这些定制,实现一个具有Material-和Cupertino灵感的漂亮的视频播放器,您可以选择chewie Flutter插件。
加载全部内容