Android?Flutter控件封裝之視頻進(jìn)度條的實現(xiàn)
視頻控制器,三方所提供的樣式,有時很難滿足我們的需求,對于此情況,我們不得不在此基礎(chǔ)上自行封裝,今天所分享的文章就是一個很簡單的控制器封裝案例,包含了基本的播放暫停,全屏和退出全屏,以及時間和進(jìn)度的展示,封裝了事件回調(diào)以及各個屬性的控制,基本上可以滿足大部分的業(yè)務(wù)需求,即便不滿足,大家也可以在此基礎(chǔ)之上拓展。
我們還是按照慣例,簡單羅列一個大綱:
1、基本的效果展示
2、具體使用和相關(guān)屬性介紹
3、控制器封裝考慮因素
4、控制器部分功能代碼刨析
5、總結(jié)及源碼地址
一、基本的效果展示
具體的效果,沒什么好說的,都是大眾常見的樣式,依次從左到右為:播放暫停按鈕,播放時間,播放進(jìn)度,總的時間,全屏及退出全屏按鈕。
可以實現(xiàn)的功能有,圖標(biāo)的動態(tài)設(shè)置,時間進(jìn)度的顏色及大小控制,以及定時器的開啟,具體的可以看第二項。
二、具體使用和相關(guān)屬性介紹
1、具體使用
作為一個Widget,大家可以隨意使用,單獨亦或者和視頻播放器綁定使用。
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> | 視頻播放點擊 |
onVideoFullScreenClick | ValueChanged<bool> | 視頻全屏點擊點擊 |
onVideoChanged | ValueChanged<int> | 滑動回調(diào) |
onVideoChangeStart | ValueChanged<int> | 拖動開始 |
onVideoChangeEnd | ValueChanged<int> | 拖動結(jié)束 |
isPlayed | bool | 播放控制狀態(tài),暫停還是開始 |
isFullScreen | bool | 是否是全屏 |
三、控制器封裝考慮因素
視頻控制器雖然說簡單,但需要考慮的因素還是比較多的,比如點擊播放和暫停,全屏和退出全屏的事件回調(diào),拖動進(jìn)度除了更改自身進(jìn)度也要更改時間進(jìn)度,傳遞的時間換算,定時的開啟和關(guān)閉等等都是需要解決的。
1、基本的UI設(shè)定
控制器的UI一定是基于設(shè)計同學(xué)所定的UI稿,否則就要以技術(shù)驅(qū)動設(shè)計更改,一般很難,不過也有特殊的案例存在。所以在封裝的時候,要么基于UI稿,要么就是動態(tài)可配置,通過屬性更改基本的樣式或者位置。
2、拖動進(jìn)度的實現(xiàn)
拖動進(jìn)度就比較簡單了,使用的是原生提供的Slider,也就是滑桿,類似于Android中的SeekBar,需要注意的是,顏色等屬性的動態(tài)配置。
3、時間的換算和進(jìn)度的綁定
時間的換算,需要把傳入的時間戳,轉(zhuǎn)化為我們所需要的時間格式,也就是時分秒的格式,這里使用了intl國際化的插件,主要用到到格式轉(zhuǎn)換DateFormat。
4、定時器的控制
定時器很簡單,實例化一個Timer即可,但是,什么時候開始,什么時候暫停都是我們需要考慮的,一般情況下,直接和視頻播放器進(jìn)行綁定,直接更改進(jìn)度即可,就不用這個定時,如果要用,可以用一個屬性控制;在需要定時的情況下,點擊暫停,需要暫停定時,除此之外播放完畢后也需要暫停定時;當(dāng)拖動完畢后,需要開啟定時,點擊播放,也需要開啟定時,所以,對于定時器控制這一塊,一定要縷清楚。
四、控制器部分功能代碼刨析
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)點擊事件,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)點擊開始播放按鈕時,如果使用定時,就要開啟,3、當(dāng)播放完畢后,再次拖動,也需要開啟定時。
暫停定時場景:1、點擊暫停視頻時,關(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(); //取消計時器 _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)度條的實現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Android Flutter視頻進(jìn)度條的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android ViewDragHelper實現(xiàn)京東、淘寶拖拽詳情功能的實現(xiàn)
這篇文章主要介紹了Android ViewDragHelper實現(xiàn)京東、淘寶拖拽詳情,實現(xiàn)這種效果大概分為三種方式,具體哪三種方式大家通過本文了解下吧2018-04-04Android 自定義驗證碼輸入框的實例代碼(支持粘貼連續(xù)性)
這篇文章主要介紹了Android 自定義驗證碼輸入框的實例代碼(支持粘貼連續(xù)性),代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-10-10Android中TabLayout結(jié)合ViewPager實現(xiàn)頁面切換
這篇文章主要為大家詳細(xì)介紹了Android中TabLayout結(jié)合ViewPager實現(xiàn)頁面切換效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12