【flutter列表播放器】

视频播放器类

dart 复制代码
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,
    @required this.url,
    @required this.play,
    @required this.articleId,
    @required this.callback,
    @required this.joinType,
    @required this.wantHaveType,
    this.pauseAspectRadio,
    this.coverUrl
  }) : super(key: key);
  @override
  _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;

  @override
  void initState() {
    super.initState();
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();

  }

  @override
  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();
      }
    }
  }

  @override
  void dispose() {
    _onDestroy();
    super.dispose();
  }

  @override
  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包裹

dart 复制代码
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

dart 复制代码
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,
                )
相关推荐
AiFlutter2 小时前
Flutter Web部署到子路径的打包指令
flutter
有趣的杰克2 小时前
Flutter InkWell组件去掉灰色遮罩
开发语言·javascript·flutter
Python私教2 小时前
Flutter动画容器
flutter
wills77715 小时前
Flutter 状态管理框架Get
flutter·react native
阳仔_10017 小时前
动态下发字体技术方案
flutter
Rudy102118 小时前
分享我在flutter中使用的MVVM框架 - 2
前端·flutter
恋猫de小郭1 天前
什么?Flutter 又要凉了? Flock 是什么东西?
flutter
lqj_本人1 天前
<大厂实战场景> ~ Flutter&鸿蒙next 解析后端返回的 HTML 数据详解
flutter·华为·架构·harmonyos·1024程序员节
MavenTalk1 天前
前端跨平台开发常见的解决方案
前端·flutter·react native·reactjs·weex·大前端