Android?Flutter控件封裝之視頻進(jìn)度條的實(shí)現(xiàn)
視頻控制器,三方所提供的樣式,有時很難滿足我們的需求,對于此情況,我們不得不在此基礎(chǔ)上自行封裝,今天所分享的文章就是一個很簡單的控制器封裝案例,包含了基本的播放暫停,全屏和退出全屏,以及時間和進(jìn)度的展示,封裝了事件回調(diào)以及各個屬性的控制,基本上可以滿足大部分的業(yè)務(wù)需求,即便不滿足,大家也可以在此基礎(chǔ)之上拓展。
我們還是按照慣例,簡單羅列一個大綱:
1、基本的效果展示
2、具體使用和相關(guān)屬性介紹
3、控制器封裝考慮因素
4、控制器部分功能代碼刨析
5、總結(jié)及源碼地址
一、基本的效果展示
具體的效果,沒什么好說的,都是大眾常見的樣式,依次從左到右為:播放暫停按鈕,播放時間,播放進(jìn)度,總的時間,全屏及退出全屏按鈕。

可以實(shí)現(xiàn)的功能有,圖標(biāo)的動態(tài)設(shè)置,時間進(jìn)度的顏色及大小控制,以及定時器的開啟,具體的可以看第二項(xiàng)。

二、具體使用和相關(guān)屬性介紹
1、具體使用
作為一個Widget,大家可以隨意使用,單獨(dú)亦或者和視頻播放器綁定使用。
VipVideoController(
totalTime: 1000 * 60,
backgroundColor: Colors.red,
progressColor: Colors.amber,
thumbColor: Colors.red,
textStyle: TextStyle(color: Colors.red),
onVideoPlayClick: (isPlay) {
print("當(dāng)前播放按鈕狀態(tài)$isPlay");
},
onVideoFullScreenClick: (isFullScreen) {
print("當(dāng)前全屏按鈕狀態(tài)$isFullScreen");
},
onVideoChanged: (position) {
//返回毫秒
print("當(dāng)前拖拽的進(jìn)度$position");
}
)2、相關(guān)屬性
| 屬性 | 類型 | 概述 |
|---|---|---|
| height | double | 設(shè)置控制器高度 |
| progressHeight | double | 進(jìn)度條高度 |
| videoPlayIcon | String | 視頻播放Icon |
| videoPauseIcon | String | 視頻暫停Icon |
| videoFullScreenIcon | String | 視頻全屏Icon |
| videoExitFullScreenIcon | String | 退出全屏Icon |
| textStyle | TextStyle | 文本樣式 |
| backgroundColor | Color | 背景顏色 |
| progressColor | Color | 進(jìn)度顏色 |
| thumbColor | Color | 拖動顏色 |
| thumbRadius | double | thumb大小 |
| playTimeMarginLeft | double | 播放時間距離左邊的距離 |
| playTimeMarginRight | double | 播放時間距離右邊的距離 |
| videoTimeMarginLeft | double | 視頻時間距離左邊的距離 |
| videoTimeMarginRight | double | 視頻時間距離右邊的距離 |
| totalTime | int | 總時長 |
| changeTime | int | 改變時長 |
| isTimer | bool | 是否需要定時 |
| onVideoPlayClick | ValueChanged<bool> | 視頻播放點(diǎn)擊 |
| onVideoFullScreenClick | ValueChanged<bool> | 視頻全屏點(diǎn)擊點(diǎn)擊 |
| onVideoChanged | ValueChanged<int> | 滑動回調(diào) |
| onVideoChangeStart | ValueChanged<int> | 拖動開始 |
| onVideoChangeEnd | ValueChanged<int> | 拖動結(jié)束 |
| isPlayed | bool | 播放控制狀態(tài),暫停還是開始 |
| isFullScreen | bool | 是否是全屏 |
三、控制器封裝考慮因素
視頻控制器雖然說簡單,但需要考慮的因素還是比較多的,比如點(diǎn)擊播放和暫停,全屏和退出全屏的事件回調(diào),拖動進(jìn)度除了更改自身進(jìn)度也要更改時間進(jìn)度,傳遞的時間換算,定時的開啟和關(guān)閉等等都是需要解決的。
1、基本的UI設(shè)定
控制器的UI一定是基于設(shè)計(jì)同學(xué)所定的UI稿,否則就要以技術(shù)驅(qū)動設(shè)計(jì)更改,一般很難,不過也有特殊的案例存在。所以在封裝的時候,要么基于UI稿,要么就是動態(tài)可配置,通過屬性更改基本的樣式或者位置。
2、拖動進(jìn)度的實(shí)現(xiàn)
拖動進(jìn)度就比較簡單了,使用的是原生提供的Slider,也就是滑桿,類似于Android中的SeekBar,需要注意的是,顏色等屬性的動態(tài)配置。
3、時間的換算和進(jìn)度的綁定
時間的換算,需要把傳入的時間戳,轉(zhuǎn)化為我們所需要的時間格式,也就是時分秒的格式,這里使用了intl國際化的插件,主要用到到格式轉(zhuǎn)換DateFormat。
4、定時器的控制
定時器很簡單,實(shí)例化一個Timer即可,但是,什么時候開始,什么時候暫停都是我們需要考慮的,一般情況下,直接和視頻播放器進(jìn)行綁定,直接更改進(jìn)度即可,就不用這個定時,如果要用,可以用一個屬性控制;在需要定時的情況下,點(diǎn)擊暫停,需要暫停定時,除此之外播放完畢后也需要暫停定時;當(dāng)拖動完畢后,需要開啟定時,點(diǎn)擊播放,也需要開啟定時,所以,對于定時器控制這一塊,一定要縷清楚。
四、控制器部分功能代碼刨析
1、基本的布局
很簡單,一個橫向的組件Row,包裹了5個子組件,進(jìn)度條使用Expanded,用于占有剩余的空間。
return SizedBox(
height: widget.height,
child: Row(
children: [
getPlayIcon(), //開始和暫停
getPlayTime(timeStampToStringDate(_progress)), //時間
Expanded(child: getSliderTheme()), //進(jìn)度
getVideoTime(timeStampToStringDate(widget.totalTime!)), //時間
getFullScreenIcon() //全屏
],
));播放Icon和全屏Icon
未傳Icon情況下,直接使用默認(rèn)的Icon,如果傳遞了,那么直接使用傳遞的,需要根據(jù)播放狀態(tài)展示播放按鈕還是暫停按鈕,全屏Icon需要根據(jù)是否全屏狀態(tài),來展示對應(yīng)的圖標(biāo),同時回調(diào)點(diǎn)擊事件,VipImage是之前封裝的圖片組件,大家可以查看以往的分享。
/*
* 獲取播放Icon
* */
Widget getPlayIcon() {
if (widget.videoPlayIcon == null) {
return InkWell(
onTap: onPlayClick,
child: Icon(_isPlayed ? Icons.pause : Icons.play_arrow),
);
} else {
return VipImage(
_isPlayed ? widget.videoPlayIcon : widget.videoPauseIcon,
onClick: onPlayClick,
);
}
}
/*
* 獲取全屏Icon
* */
Widget getFullScreenIcon() {
if (widget.videoFullScreenIcon == null) {
return InkWell(
onTap: onFullScreenClick,
child: Icon(_isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen),
);
} else {
return VipImage(
_isFullScreen
? widget.videoFullScreenIcon
: widget.videoExitFullScreenIcon,
onClick: onFullScreenClick,
);
}
}播放時長和總時長
VipText是之前封裝的文本組件,大家可以查看以往的分享,需要注意的是傳入的時間需要格式化處理,轉(zhuǎn)化為對應(yīng)的時分秒結(jié)構(gòu)。
/*
*獲取播放時長
* */
Widget getPlayTime(String text) {
return VipText(
text,
style: widget.textStyle,
marginLeft: widget.playTimeMarginLeft,
marginRight: widget.playTimeMarginRight,
);
}
/*
*獲取總的播放時長
* */
Widget getVideoTime(String text) {
return VipText(
text,
style: widget.textStyle,
marginLeft: widget.videoTimeMarginLeft,
marginRight: widget.videoTimeMarginRight,
);
}中間的進(jìn)度條
進(jìn)度條使用的是Slider,直接按照原生的Api使用即可,需要注意,最大的進(jìn)度也就是max,需要和設(shè)置的總時長綁定,還有divisions分段,需要以秒作為區(qū)分,否則在滑動改變的時候,有可能會和定時造成沖突。
Widget getSliderTheme() {
var divisions = widget.totalTime! / 1000;
return SliderTheme(
data: SliderThemeData(
//高度
trackHeight: widget.progressHeight,
//去掉長按光暈
overlayColor: Colors.transparent,
//背景顏色
inactiveTrackColor: widget.backgroundColor,
activeTrackColor: widget.progressColor,
thumbColor: widget.thumbColor,
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: widget.thumbRadius)),
child: Slider(
min: 0,
max: widget.totalTime!.toDouble(),
value: _progress.toDouble(),
divisions: divisions.toInt(),
onChangeStart: (progress) {
if (widget.onVideoChangeStart != null) {
widget.onVideoChangeStart!(progress.toInt());
}
},
onChangeEnd: (progress) {
if (widget.onVideoChangeEnd != null) {
widget.onVideoChangeEnd!(progress.toInt());
}
if (_isPlayed) {
//播放狀態(tài)下,如果定時,才會執(zhí)行
_startTimer();
}
},
onChanged: (double value) {
setState(() {
_progress = value.toInt();
});
//回調(diào)當(dāng)前進(jìn)度
if (widget.onVideoChanged != null) {
widget.onVideoChanged!(_progress);
}
},
),
);
}2、時間轉(zhuǎn)換
前邊有說過使用的是intl國際化插件,主要用到的是dateFormat.format()。
/*
* 時間戳轉(zhuǎn)換時間
* */
String timeStampToStringDate(int time) {
String format = time < 1000 * 60 * 60 ? TimeUtil.m_s : TimeUtil.h_m_s;
return TimeUtil.getTimeStampToStringDate(time, format: format);
}
/*
* 時間戳轉(zhuǎn)時間
* */
static String getTimeStampToStringDate(int timeStamp,
{String format = y_M_d}) {
var dateFormat = DateFormat(format);
var dateTime = DateTime.fromMillisecondsSinceEpoch(timeStamp);
return dateFormat.format(dateTime);
}3、定時操作
定時需要注意的是,在需要定時的時候再開啟,比如定義的屬性為true時,就執(zhí)行開啟動作,當(dāng)開啟定時后,我們的進(jìn)度大于總時長時,就需要暫停定時。
開啟定時場景:1、定義的屬性為true時,進(jìn)入直接開啟定時。2、當(dāng)點(diǎn)擊開始播放按鈕時,如果使用定時,就要開啟,3、當(dāng)播放完畢后,再次拖動,也需要開啟定時。
暫停定時場景:1、點(diǎn)擊暫停視頻時,關(guān)閉定時,2、播放結(jié)束時,關(guān)閉定時,3、頁面銷毀時,也需要關(guān)閉定時。
/*
* 開啟定時
* */
void _startTimer() {
if (widget.isTimer! && _timer == null) {
//開啟定時,一秒執(zhí)行一次
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (_progress >= widget.totalTime!) {
_pauseTimer();
} else {
setState(() {
_progress += 1000;
});
widget.onVideoChanged!(_progress);
}
});
}
}
/*
* 暫停定時
* */
void _pauseTimer() {
if (_timer != null) {
_timer!.cancel(); //取消計(jì)時器
_timer = null;
}
}五、總結(jié)及源碼地址
源碼是一個簡單的文件,地址:github.com/AbnerMing888/flutter_widget/blob/master/lib/ui/widget/vip_video_controller.dart
源碼中有用到之前封裝的組件,請大家悉知,目前所封裝的組件,樣式和圖標(biāo)都是可以更換的,但是有一個就是位置還有組件是否顯示沒有封裝,不過源碼已經(jīng)貼出,大家可以在源碼基礎(chǔ)之上進(jìn)行更改。
以上就是Android Flutter控件封裝之視頻進(jìn)度條的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Android Flutter視頻進(jìn)度條的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android 給RecyclerView添加分割線的具體步驟(分享)
下面小編就為大家?guī)硪黄狝ndroid 給RecyclerView添加分割線的具體步驟(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04
Android實(shí)現(xiàn)View拖拽跟隨手指移動效果
這篇文章主要介紹了Android實(shí)現(xiàn)View拖拽跟隨手指移動效果,主要使用setTranslationX() 和setTranslationY() 屬性方法實(shí)現(xiàn)的,需要的朋友參考下吧2017-08-08
Android中 TeaScreenPopupWindow多類型篩選彈框功能的實(shí)例代碼
這篇文章主要介紹了Android TeaScreenPopupWindow多類型篩選彈框功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-06-06
ViewPager實(shí)現(xiàn)漂亮的引導(dǎo)頁
這篇文章主要為大家詳細(xì)介紹了ViewPager實(shí)現(xiàn)漂亮的引導(dǎo)頁,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08

