首页 > 其他分享 >flutter 技术选型 —— 视频播放器插件

flutter 技术选型 —— 视频播放器插件

时间:2022-08-16 21:24:16浏览次数:55  
标签:播放器 插件 widget player key child override super flutter

chewie

依赖:video_player + chewie
缺点:ui 简陋,无法后台播放

class VideoPlayerScreen extends StatefulWidget {
  const VideoPlayerScreen({Key? key}) : super(key: key);

  @override
  State<VideoPlayerScreen> createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  VideoPlayerController? videoPlayerController;
  ChewieController? chewieController;

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

  Future<void> initVideoPlayer() async {
    videoPlayerController = VideoPlayerController.network('https://sdx2.oss-cn-beijing.aliyuncs.com/qcloud.mp4');

    await videoPlayerController?.initialize();

    setState(() {
      chewieController = ChewieController(
        videoPlayerController: videoPlayerController!,
        autoPlay: true,
        looping: true,
      );
    });
  }

  @override
  void dispose() {
    videoPlayerController?.dispose();
    chewieController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: chewieController == null
          ? const LinearProgressIndicator()
          : ListView(
              children: [
                AspectRatio(
                  aspectRatio: 16 / 9,
                  child: Chewie(
                    controller: chewieController!,
                  ),
                ),
              ],
            ),
    );
  }
}

fijkplayer

依赖:fijkplayer
缺点:需要定制 ui,iOS 上无法后台播放

class Fijkplayer extends StatefulWidget {
  const Fijkplayer({Key? key}) : super(key: key);

  @override
  State<Fijkplayer> createState() => _FijkplayerState();
}

class _FijkplayerState extends State<Fijkplayer> {
  final FijkPlayer player = FijkPlayer();

  @override
  void initState() {
    super.initState();
    player.setDataSource('https://sdx2.oss-cn-beijing.aliyuncs.com/qcloud.mp4', autoPlay: true);
  }

  @override
  void dispose() {
    super.dispose();
    player.release();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: FijkView(
          color: Colors.black,
          fsFit: FijkFit.fitHeight,
          player: player,
          panelBuilder: (FijkPlayer player, FijkData data, BuildContext context, Size viewSize, Rect texturePos) {
            return CustomFijkPanel(
                player: player,
                buildContext: context,
                viewSize: viewSize,
                texturePos: texturePos);
          },
        ),
      ),
    );
  }
}

class CustomFijkPanel extends StatefulWidget {
  final FijkPlayer player;
  final BuildContext? buildContext;
  final Size? viewSize;
  final Rect? texturePos;

  const CustomFijkPanel({
    required this.player,
    this.buildContext,
    this.viewSize,
    this.texturePos,
  });

  @override
  _CustomFijkPanelState createState() => _CustomFijkPanelState();
}

class _CustomFijkPanelState extends State<CustomFijkPanel> {
  FijkPlayer get player => widget.player;
  bool _playing = false;

  @override
  void initState() {
    super.initState();
    //初始化
    _playing = player.state == FijkState.started;
    widget.player.addListener(_playerValueChanged);
  }

  void _playerValueChanged() {
    FijkValue value = player.value;

    print("playing ${value.state}");
    bool playing = (value.state == FijkState.started);
    setState(() {
      _playing = playing;
    });

  }

  @override
  Widget build(BuildContext context) {
    Rect rect = Rect.fromLTRB(max(0.0, widget.texturePos?.left ?? 0), max(0.0, widget.texturePos?.top ?? 0),
        min(widget.viewSize?.width ?? 0, widget.texturePos?.right ?? 0), min(widget.viewSize?.height ?? 0, widget.texturePos?.bottom ?? 0));

    return Positioned.fromRect(
      rect: rect,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          IconButton(
            icon: Icon(
              _playing ? Icons.pause : Icons.play_arrow,
              color: Colors.white,
            ),
            onPressed: () {
              _playing ? widget.player.pause() : widget.player.start();
            },
          ),
          IconButton(
            icon: Icon(
              widget.player.value.fullScreen ? Icons.fullscreen_exit : Icons.fullscreen,
              color: Colors.white,
            ),
            onPressed: () {
              widget.player.value.fullScreen ? widget.player.exitFullScreen() : widget.player.enterFullScreen();
            },
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    player.removeListener(_playerValueChanged);
  }
}

flickplayer (推荐)

依赖:flick_video_player
缺点:无法后台播放

class FlickPlayerScreen extends StatefulWidget {
  const FlickPlayerScreen({Key? key}) : super(key: key);

  @override
  State<FlickPlayerScreen> createState() => _FlickPlayerScreenState();
}

class _FlickPlayerScreenState extends State<FlickPlayerScreen> {
  late FlickManager flickManager;

  @override
  void initState() {
    super.initState();
    flickManager = FlickManager(
      videoPlayerController: VideoPlayerController.network(
          "https://sdx2.oss-cn-beijing.aliyuncs.com/qcloud.mp4"),
    );
  }

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

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: AspectRatio(
          aspectRatio: 16/9,
          child: FlickVideoPlayer(
            flickManager: flickManager,
            preferredDeviceOrientationFullscreen: [
              DeviceOrientation.landscapeLeft,
              DeviceOrientation.landscapeRight,
            ],
            flickVideoWithControls: FlickVideoWithControls(
              videoFit: BoxFit.contain,
              controls: CustomOrientationControls(
              ),
            ),
            flickVideoWithControlsFullscreen: FlickVideoWithControls(
              videoFit: BoxFit.contain,
              controls: SafeArea(child: CustomOrientationControls()),
            ),
          ),
        ),
      ),
    );
  }
} 

class CustomOrientationControls extends StatelessWidget {
  const CustomOrientationControls(
      {Key? key, this.iconSize = 25, this.fontSize = 12})
      : super(key: key);
  final double iconSize;
  final double fontSize;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned.fill(
          child: FlickShowControlsAction(
            child: FlickSeekVideoAction(
              child: Center(
                child:  FlickAutoHideChild(
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: FlickPlayToggle(size: 50),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
        Positioned.fill(
          child: FlickAutoHideChild(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.end,
                children: <Widget>[
                  Row(
                    children: <Widget>[
                      Row(
                        children: <Widget>[
                          FlickCurrentPosition(
                            fontSize: fontSize,
                          ),
                          Text(
                            ' / ',
                            style: TextStyle(
                                color: Colors.white, fontSize: fontSize),
                          ),
                          FlickTotalDuration(
                            fontSize: fontSize,
                          ),
                        ],
                      ),
                      Expanded(
                        child: Container(),
                      ),
                      FlickFullScreenToggle(
                        size: iconSize,
                      ),
                    ],
                  ),
                  FlickVideoProgressBar(
                    flickProgressBarSettings: FlickProgressBarSettings(
                      height: 5,
                      handleRadius: 5,
                      curveRadius: 50,
                      backgroundColor: Colors.white24,
                      bufferedColor: Colors.white38,
                      playedColor: Colors.red,
                      handleColor: Colors.red,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );
  }
}

标签:播放器,插件,widget,player,key,child,override,super,flutter
From: https://www.cnblogs.com/lemos/p/16593024.html

相关文章

  • flutter 基础 —— 缓存页面与滚动位置等信息
    一、缓存页面比如Tab切换,旧的Tab可能被销毁,我们需要做缓存。解决方法:如果是PageView可以更改allowImplicitScrolling值为true,会缓存前后各一页。其它组件,可以......
  • VS Code常用插件
    VSCode常用插件一、插件的下载打开VScode之后点击右侧带有小方块的图标在上方的输入框中输入想要下载的插件的名称即可二、插件的种类Chinese(Simplified)Langu......
  • flutter 效果实现 —— NestedScrollView 嵌套滚动(多固定头)
    效果代码注:请添加依赖sliver_toolsclassMultiPinNestedTabsPageextendsStatelessWidget{MultiPinNestedTabsPage({Key?key}):super(key:key);final......
  • Vue+Leaflet.PM插件实现创建和编辑几何图形(点、线、面、圆等)
    场景Vue+Leaflet实现加载OSM显示地图:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/122317394在上面加载显示OSM的基础上,使用Leaflet.pm插件实现在页面上......
  • 备份谷歌或其他浏览器插件
    原文链接备份谷歌或其他浏览器插件1浏览器地址栏输入:chrome://extensions/,选择开发模式,单击打包扩展程序,可以看到一个“扩展程序根目录”输入框。2进入浏览器插件的......
  • flutter系列之:flutter架构什么的,看完这篇文章就全懂了
    目录简介Flutter的架构图embedderengineFlutterframeworkWidgetsWidgets的可扩展性Widgets的状态管理渲染和布局总结简介Flutter是google开发的一个跨平台的UI构建工具,f......
  • rabbitmq延时插件的安装
    目录rabbitmq延时插件的安装1下载具体操作2将插件拷贝至容器中3进入容器,并查看插件4启动插件并重启容器5查看是否生效相关文档rabbitmq延时插件的安装资料参考地址......
  • flutter 常见组件的特殊用法 —— SliverAppBar
    SliverAppBar的组成特殊属性说明primary:true不同于AppBar通常有Scaffold包裹,其最大高度由父类约束。SliverAppBar完全由自身决定。当primary等于true时,其......
  • 开发Chrome插件,实现网站自动登录
    近期被一个事情困扰着,我们采购了一款软件,里面有一个数据大屏页,当登录过期后,数据就会保持原状,不再更新。和供应商反馈了很多次,都无法彻底解决数据显示的问题,没办法,自己......
  • flutter 常见组件的特殊用法 —— AppBar
    AppBar的高度与PreferredSizeWidget通常可以观察到Scaffold.appBar与AppBar.bottom属性,要求其值必须是PreferredSizeWidget(典型的是AppBar与TabBar组件)。abst......