【flutter列表播放器】
视频播放器类
import 'package:jade/configs/PathConfig.dart';
import 'package:jade/utils/Utils.dart';
import 'package:model/user_share/reward_pool_model.dart';
import 'package:pages/user_share/view/user_share_article_detail_page.dart';
import 'package:util/navigator_util.dart';
import 'package:util/provider_util.dart';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:visibility_detector/visibility_detector.dart';
class VideoWidgetUserShare extends StatefulWidget {
final String url;
bool play;
final String articleId;
final Function callback;
final int joinType;
final int wantHaveType;
final double pauseAspectRadio;
final String coverUrl;
VideoWidgetUserShare({
Key key,
this.url,
this.play,
this.articleId,
this.callback,
this.joinType,
this.wantHaveType,
this.pauseAspectRadio,
this.coverUrl
}) : super(key: key);
_VideoWidgetUserShareState createState() => _VideoWidgetUserShareState();
}
class _VideoWidgetUserShareState extends State<VideoWidgetUserShare> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
double aspectRadio = 16.0 / 9.0;
ConnectivityResult _connectivityResult;
var _isVisible = true;
double _sizeWidth = 16.0;
double _sizeHeight = 9.0;
void initState() {
super.initState();
}
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
}
void didUpdateWidget(VideoWidgetUserShare oldWidget) {
super.didUpdateWidget(oldWidget);
_connectivityResult = providerOf<RewardPoolModel>().connectivityResult;
/*if (oldWidget.play != widget.play) {
if (widget.play && _connectivityResult == ConnectivityResult.wifi) {
_controller.play();
} else {
_controller.pause();
}
}*/
if (oldWidget.play != widget.play) {
if (widget.play && _connectivityResult == ConnectivityResult.wifi && _isVisible == true) {
print('=播放器初始化并播放===');
_init();
} else {
print('=播放器销毁释放===');
_onDestroy();
}
}
}
void dispose() {
_onDestroy();
super.dispose();
}
Widget build(BuildContext context) {
return widget.play && _controller != null
? _videoPlayerView()
: _coverImageView();
}
//初始化播放器控制器
_init(){
print('视频播放器初始化==========');
if(mounted){
_controller = VideoPlayerController.network(
widget.url,
);
_controller.setVolume(0);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
if (_controller.value.size.width < _controller.value.size.height) {
//宽度小于高度: 竖屏视频
_sizeWidth = 9.0;
_sizeHeight = 16.0;
}else{
//宽度大于高度: 横屏视频
_sizeWidth = 16.0;
_sizeHeight = 9.0;
}
_controller.setLooping(true);
});
/*_controller.addListener(() {
print('position:${_controller.value.position}');
});*/
_connectivityResult = providerOf<RewardPoolModel>().connectivityResult;
if (widget.play && _connectivityResult == ConnectivityResult.wifi) {
_controller.play();
}
}
}
//销毁播放器控制器
_onDestroy(){
if(_controller != null){
_controller.dispose();
_controller = null;
}
}
//视频播放器布局
_videoPlayerView(){
return VisibilityDetector(
key: Key(widget.url),
onVisibilityChanged: (visibilityInfo){
_isVisible = visibilityInfo.visibleFraction > 0;
print('视频播放器小部件是否可见====$_isVisible');
if(_isVisible == false){
widget.play = false;
_onDestroy();
}
// setState(() {});
},
child: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
return snapshot.connectionState == ConnectionState.done
? Stack(
children: [
Center(
child: GestureDetector(
onTap: () {
setState(() {
if(_controller != null){
_controller.pause();
}
});
},
child:
/*ClipRRect(
borderRadius: BorderRadius.circular(2),
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller)
))*/
SizedBox.expand(
child: FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: _sizeWidth,height: _sizeHeight,
child: VideoPlayer(_controller)),
)
)
),
),
Center(
child: Offstage(
offstage: _controller.value.isPlaying,
child: Image.asset(PathConfig.iconPause,
width: 40,
height: 40,
),
),
),
],
)
: _loadingView();
},
)
);
}
//显示封面图布局
_coverImageView(){
return Stack(
alignment: Alignment.center,
children: [
widget.coverUrl != null ?
SizedBox(
width: double.infinity,
height: double.infinity,
child: Utils().roundedImage(widget.coverUrl, 5,fit: BoxFit.cover)
) : SizedBox(
width: double.infinity,
height: double.infinity
),
Image.asset(PathConfig.iconPause,
width: 40,
height: 40,
)
],
);
}
//视频播放器初始化,加载中封面
_loadingView(){
return Stack(
alignment: Alignment.center,
children: [
widget.coverUrl != null ?
SizedBox(
width: double.infinity,
height: double.infinity,
child: Utils().roundedImage(widget.coverUrl, 5,fit: BoxFit.cover)
) : SizedBox(
width: double.infinity,
height: double.infinity
),
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
strokeWidth: 2,
)
],
);
}
}
列表ItemView中视频部分用InViewNotifierWidget包裹
Container(
child: InViewNotifierWidget(
id: '$index',
builder: (BuildContext context, bool isInView,
Widget child) {
return ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Container(
width: Utils().screenWidth(context),
height: Utils().screenWidth(context) * 0.5625,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(5)),
child: VideoWidgetUserShare(
key: ValueKey(videoUrl),
play: isInView,
url: videoUrl,
coverUrl: coverUrl,
callback: (value) {}
),
)
);
},
),
)
列表使用InViewNotifierList
ScrollController _scrollController = ScrollController();
void initState() {
_scrollController.addListener(() {
double pixels = _scrollController.position.pixels;
//以前版本中用来上滑时隐藏tabBar导航栏的
/*if (pixels >= _prePixels) {
_prePixels = pixels;
providerOf<MainModel>().setTabBarHeight(tabBarHeight - pixels);
} else {
providerOf<MainModel>().setTabBarHeight(tabBarHeight);
}*/
if (pixels == _scrollController.position.maxScrollExtent) {
_doLoadMore();
}
});
}
InViewNotifierList(
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.all(0),
scrollDirection: Axis.vertical,
initialInViewIds: ['0'],
isInViewPortCondition: (double deltaTop, double deltaBottom,
double viewPortDimension) {
return deltaTop < (0.5 * viewPortDimension) &&
deltaBottom > (0.5 * viewPortDimension);
},
itemCount: articleList.length + 2,
builder: (BuildContext listContext, int index) {
if (index == 0) {
if(_bannerList.isNotEmpty){
return BannerWidget(bannerList: _bannerList,swiperController: swiperController,);
}else{
return Container();
}
} else if (index == articleList.length + 1) {
if (articleList.isEmpty) {
return Container(
margin: EdgeInsets.only(top: 75),
child: Image.asset(S.current.l31),
);
}
return _buildLoadMore();
} else {
return _buildContentItem(
listContext,
articleList[index - 1], index - 1);
}
},
controller: _scrollController,
)