当前位置: 首页 > article >正文

【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,
                )

http://www.kler.cn/a/376122.html

相关文章:

  • Vue3+TypeScript+Vite 后台管理项目_登录页面开发实战
  • 如何在Linux下部署自己的ZFile开源网盘
  • 【数据结构】宜宾大学-计院-实验六
  • 【Git】Git常用命令
  • 基于 webpack 项目接入 vite 你可能需要注意的点
  • 直流电机在液压泵领域的应用
  • 基于Spring Boot的网络考试系统设计与实现(源码+定制+开发)网络考试管理平台、智能考试评估系统、题库管理系统设计、Spring Boot考试平台开发
  • 数字IC后端实现之Innovus Place跑完density爆涨案例分析
  • stable diffusion webui API调用示例,调用参数,override_settings参数
  • 时光书屋--
  • 标签之文字排版,图片,链接,音视频(HTML) 基础版
  • 4、liunx开机启动详解
  • 信息学科平台设计与实现:Spring Boot技术详解
  • 【Android】常见问题集锦
  • 112. gui辅助调节光源阴影
  • 浅谈鸿蒙生态崛起的机遇
  • LeetCode647:回文子串
  • 大规模语言模型:从理论到实践(1)
  • Python 工具库每日推荐 【Sphinx】
  • 李飞飞团队新突破:低成本高泛化机器人训练法,零样本迁移成功率90%!
  • 【AI开源项目】FastGPT- 深入解析 FastGPT 的知识库逻辑与检索机制:让 AI 更聪明的秘密
  • 20+款数据库DBA常用工具,助你高效管理
  • b站小土堆PyTorch视频学习笔记(二)
  • Spring Boot中发送邮件步骤
  • Web API简洁架构:3个热门开源项目汇总!
  • 如何设计一个支撑数亿用户的系统?