詳解Flutter中視頻播放器插件的使用教程
您已經(jīng)看到很多包含視頻內(nèi)容的應(yīng)用程序,比如帶有視頻教程的食譜應(yīng)用程序、電影應(yīng)用程序和體育相關(guān)的應(yīng)用程序。您是否想知道如何將視頻內(nèi)容添加到您的下一個(gè)Flutter應(yīng)用程序中?
從頭開(kāi)始實(shí)現(xiàn)視頻功能將是一項(xiàng)繁重的任務(wù)。但有幾個(gè)插件可以讓開(kāi)發(fā)者的生活變得輕松。視頻播放器插件是可用于 Flutter 的最佳插件之一,可滿(mǎn)足這一要求。
在這篇文章中,您將學(xué)習(xí)如何應(yīng)用視頻播放器插件以及控制視頻播放器的不同功能。
我們將討論這些主題。
- 創(chuàng)建一個(gè)新的視頻播放器
- 添加播放和暫停按鈕
- 創(chuàng)建一個(gè)快進(jìn)
- 添加一個(gè)視頻進(jìn)度指示器
- 應(yīng)用視頻的字幕
創(chuàng)建一個(gè)新的視頻播放器
在使用視頻播放器插件之前,你應(yīng)該把它添加到你的pubspec.yaml 文件中。當(dāng)你打開(kāi)pubspec.yaml 文件時(shí),你可以看到運(yùn)行你的應(yīng)用程序所需的一些配置和依賴(lài)性。我們的視頻播放器插件應(yīng)該被添加到dependencies 塊下。
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
video_player: 2.1.15 //video player
該插件的當(dāng)前版本是2.1.15 ,但你可以通過(guò)查看插件頁(yè)面在這里添加最新版本。如果你保存文件時(shí)是在VS Code中,它會(huì)自動(dòng)下載該插件。如果不是,打開(kāi)終端,寫(xiě)flutter pub get 來(lái)下載該插件。
進(jìn)入你想添加該插件的文件,并導(dǎo)入video_player.dart 文件。
import 'package:video_player/video_player.dart';
現(xiàn)在你可以在你的項(xiàng)目中使用視頻播放器插件了。
有幾種方法來(lái)加載視頻。讓我們從資產(chǎn)中加載我們的例子。在項(xiàng)目的根層創(chuàng)建一個(gè)assets/video文件夾,在該文件夾內(nèi)添加一個(gè)視頻。然后在pubspec.yaml ,在assets 部分,指定文件路徑,如下所示。
assets:
- assets/video/video.mp4
讓我們創(chuàng)建一個(gè)單獨(dú)的有狀態(tài)的部件,稱(chēng)為VideoPlayerWidget ,以插入我們的視頻播放器相關(guān)的實(shí)現(xiàn)。
你可以在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 關(guān)鍵字來(lái)指定,因?yàn)槲覀冊(cè)谶@一行中仍然沒(méi)有定義視頻播放器控制器,我們將在后面做這個(gè)。在initState 里面,videoPlayerController 已經(jīng)和資產(chǎn)的路徑一起被初始化。
當(dāng)初始化完成后,它改變了狀態(tài)并重建了小部件。你可以在初始化后開(kāi)始播放視頻。
取代assets ,你可以使用視頻的URL。為了訪問(wèn)網(wǎng)絡(luò),你應(yīng)該給Android和iOS添加互聯(lián)網(wǎng)權(quán)限配置。
從根目錄下,進(jìn)入ios/Runner ,打開(kāi)info.plist 文件。然后,在該文件中添加以下配置。
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
接下來(lái),去android/app/src/main ,并打開(kāi)AndroidManifest.xml 。然后,向其添加以下代碼。
<uses-permission android:name="android.permission.INTERNET"/>
現(xiàn)在你可以把asset 改為network ,并在那里添加視頻URL。
@override
void initState() {
super.initState();
_videoPlayerController =
VideoPlayerController.network('video_url_here')
..initialize().then((_) {
setState(() {});
_videoPlayerController.play();
});
}即使初始化已經(jīng)完成,也應(yīng)該有辦法在用戶(hù)界面中顯示播放器。VideoPlayer widget可以用來(lái)做到這一點(diǎn)。為了使它工作,你應(yīng)該把控制器作為第一個(gè)參數(shù)傳遞給VideoPlayer widget。
在顯示VideoPlayer widget之前,最好先檢查初始化是否成功。
@override
Widget build(BuildContext context) {
return Center(
child: _videoPlayerController.value.isInitialized ? VideoPlayer(_videoPlayerController) : Container(),
);
}
現(xiàn)在你可以看到屏幕上的視頻了。但是有一個(gè)小問(wèn)題:它的長(zhǎng)寬比不合適。這可以通過(guò)使用AspectRatio widget來(lái)解決。視頻播放器提供了一個(gè)適當(dāng)?shù)囊曨l長(zhǎng)寬比,你可以使用這個(gè)值來(lái)設(shè)置為AspectRatio widget。
@override
Widget build(BuildContext context) {
return Center(
child: _videoPlayerController.value.isInitialized ? AspectRatio(aspectRatio:
_videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController)
) : Container(),
);
}現(xiàn)在你可以看到具有適當(dāng)長(zhǎng)寬比的視頻。

添加播放和暫停按鈕
首先,讓我們把視頻播放器小部件包在一個(gè)列小部件里面,因?yàn)槲覀儜?yīng)該把播放和暫停按鈕放在播放器下面。在播放器小組件之后的列內(nèi),讓我們?cè)谝粋€(gè)Row 小組件內(nèi)添加兩個(gè)ElevatedButton 小組件,在這些按鈕之間讓我們添加一個(gè)Padding 小組件以保持一些呼吸空間。
對(duì)每個(gè)ElevatedButton ,添加相關(guān)的Icons ,作為子部件。然后在播放按鈕onPressed 的回調(diào)里面,你可以參考_videoPlayerController ,并調(diào)用play 方法來(lái)開(kāi)始播放視頻。在暫停按鈕里面,使用pause 方法而不是播放。
現(xiàn)在你可以刪除之前在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))
],
)
],
);
}
另外,你可以給按鈕添加樣式,得到一個(gè)看起來(lái)很圓的按鈕,這通常是在視頻播放器中。
@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))
],
)
],
);
}
創(chuàng)建一個(gè)快進(jìn)
在實(shí)現(xiàn)快進(jìn)之前,讓我們思考一下我們需要什么。首先,應(yīng)該有一個(gè)訪問(wèn)當(dāng)前視頻位置/時(shí)間的方法和一個(gè)設(shè)置新值的方法??刂破鞯?code>seekTo 方法允許我們?yōu)橐曨l設(shè)置持續(xù)時(shí)間。
你可以通過(guò)視頻播放器value 屬性訪問(wèn)當(dāng)前的視頻位置,就像下面這樣。
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))像這樣,當(dāng)用戶(hù)點(diǎn)擊按鈕時(shí),你也可以通過(guò)減少10 秒來(lái)實(shí)現(xiàn)向后倒轉(zhuǎn)。
添加一個(gè)視頻進(jìn)度指示器
視頻播放器插件提供了內(nèi)置的功能來(lái)添加一個(gè)進(jìn)度條以及一些控件。你可以使用VideoProgressIndicator widget來(lái)實(shí)現(xiàn)這個(gè)功能。
作為第一個(gè)參數(shù),你必須傳遞控制器并設(shè)置allowScrubbing 屬性。allowScrubbing 屬性將允許用戶(hù)通過(guò)觸摸小組件來(lái)滑動(dòng)進(jìn)度。通過(guò)啟用這個(gè),用戶(hù)可以跳到視頻的不同時(shí)間戳。此外,你還可以單獨(dú)控制尋求欄的背景顏色、緩沖區(qū)顏色和播放區(qū)顏色。
VideoProgressIndicator(
_videoPlayerController,
allowScrubbing: true,
colors: VideoProgressColors(
backgroundColor: Colors.red,
bufferedColor: Colors.black,
playedColor: Colors.blueAccent),
)

應(yīng)用視頻的字幕
字幕對(duì)你的應(yīng)用程序來(lái)說(shuō)需要兩樣?xùn)|西。第一個(gè)是不同時(shí)期的段落/單詞列表,第二個(gè)是在視頻播放時(shí)顯示這些標(biāo)題的方法。為此,應(yīng)該有一種方法來(lái)為時(shí)間變化添加一個(gè)監(jiān)聽(tīng)器。
視頻播放器包含一個(gè)addListener 方法,每秒鐘執(zhí)行一次。你可以使用這個(gè)監(jiān)聽(tīng)器,根據(jù)不同的時(shí)間段為視頻播放器提供字幕。
首先,讓我們創(chuàng)建一個(gè)Map ,其中包含時(shí)間作為一個(gè)鍵,字幕文本作為一個(gè)值。在Map ,時(shí)間的單位將是秒。
Map<int,String> captions = {
5:"First subtitle",
20:"Second subtitle"
};
接下來(lái),在初始化視頻播放器時(shí)注冊(cè)一個(gè)Listener 。在回調(diào)里面,你可以檢查視頻是否正在播放,如果視頻正在播放,則獲得當(dāng)前的時(shí)間為秒。然后,如果當(dāng)前值包含在captions 地圖中,我們可以像下面這樣將該值設(shè)置為選定的標(biāo)題。
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();
});
}現(xiàn)在你可以使用ClosedCaption 來(lái)設(shè)置那個(gè)選定的標(biāo)題。你可以給標(biāo)題文本添加一些樣式,以獲得更好的可見(jiàn)性。
ClosedCaption(
text: selectedCaption,textStyle: TextStyle(fontSize: 15,color: Colors.white),)

但是,每次標(biāo)題改變時(shí),建立主部件并不是好的做法。因此,我們應(yīng)該把標(biāo)題邏輯提取到一個(gè)單獨(dú)的小部件。
要注冊(cè)一個(gè)監(jiān)聽(tīng)器,你應(yīng)該把視頻控制器傳遞給一個(gè)新創(chuàng)建的子部件。
從那里,你可以在子部件內(nèi)注冊(cè)監(jiān)聽(tīng)器。
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),);
}
}現(xiàn)在我們可以在之前創(chuàng)建的欄目?jī)?nèi)添加這個(gè)小部件,并將_videoPlayerController 作為參數(shù)傳遞。你可以在把小部件添加到樹(shù)上之前檢查視頻播放器是否已經(jīng)被初始化,就像下面這樣。
_videoPlayerController.value.isInitialized ? VCaption(_videoPlayerController) : Container(),
你可以使用Stack widget在視頻頂部顯示這些字幕,而不是在視頻下面顯示那些字幕。字幕以及進(jìn)度指示器已經(jīng)被移到了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),
))
],
)

結(jié)論
使用視頻播放器插件而不是從頭開(kāi)始實(shí)現(xiàn)一個(gè)視頻播放器,可以節(jié)省大量的開(kāi)發(fā)時(shí)間,并提供所有開(kāi)箱即用的功能。
如果您想超越這些定制,實(shí)現(xiàn)一個(gè)具有Material-和Cupertino靈感的漂亮的視頻播放器,您可以選擇chewie Flutter插件。
以上就是詳解Flutter中視頻播放器插件的使用教程的詳細(xì)內(nèi)容,更多關(guān)于Flutter視頻播放器插件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android四大組件之廣播BroadcastReceiver詳解
Android開(kāi)發(fā)的四大組件分別是:活動(dòng)(activity),用于表現(xiàn)功能;服務(wù)(service),后臺(tái)運(yùn)行服務(wù),不提供界面呈現(xiàn);廣播接受者(Broadcast Receive),勇于接收廣播;內(nèi)容提供者(Content Provider),支持多個(gè)應(yīng)用中存儲(chǔ)和讀取數(shù)據(jù),相當(dāng)于數(shù)據(jù)庫(kù),本篇著重介紹廣播組件2021-11-11
Android之內(nèi)置和外置sdcard路徑顯示并且寫(xiě)入數(shù)據(jù)的方法
今天小編就為大家分享一篇Android之內(nèi)置和外置sdcard路徑顯示并且寫(xiě)入數(shù)據(jù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
基于Flutter實(shí)現(xiàn)風(fēng)車(chē)加載組件的制作
Flutter官方提供了諸如 CircularProgressIndicator和 LinearProgressIndicator兩種常見(jiàn)的加載指示組件,但是說(shuō)實(shí)話,實(shí)在太普通,所以本文將用Flutter自定義一個(gè)風(fēng)車(chē)加載組件,需要的可以參考一下2022-03-03
Android編程獲取并設(shè)置Activity亮度的方法
這篇文章主要介紹了Android編程獲取并設(shè)置Activity亮度的方法,涉及Android針對(duì)屏幕亮度的相關(guān)操作技巧,需要的朋友可以參考下2015-12-12
android整數(shù)二分模板徹底解決邊界問(wèn)題
這篇文章主要介紹了android整數(shù)二分模板徹底解決邊界問(wèn)題,主要利用android整數(shù)二分模板解決邊界問(wèn)題,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-12-12
Android RecyclerView添加頭部和底部的方法
這篇文章主要為大家詳細(xì)介紹了Android RecyclerView添加頭部和底部的方法,感興趣的小伙伴們可以參考一下2016-05-05
Android 錢(qián)包支付之輸入支付密碼的實(shí)現(xiàn)步驟
這篇文章主要介紹了Android 錢(qián)包支付之輸入支付密碼,需要的朋友可以參考下2018-04-04
Android自定義View之簡(jiǎn)約風(fēng)歌詞控件實(shí)戰(zhàn)指南
一些接觸Android不久的朋友對(duì)自定義View都有一絲畏懼感,總感覺(jué)這是一個(gè)比較高級(jí)的技術(shù),但其實(shí)自定義View并不復(fù)雜,有時(shí)候只需要簡(jiǎn)單幾行代碼就可以完成了,這篇文章主要給大家介紹了關(guān)于Android自定義View之簡(jiǎn)約風(fēng)歌詞控件的相關(guān)資料,需要的朋友可以參考下2021-07-07

