在Flutter中实现视频供稿的最佳方法是什么? [英] What is the best way to implement a video feed in Flutter?

查看:211
本文介绍了在Flutter中实现视频供稿的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在扑朔迷离地构建一个应用程序,其中包含一个像TikTok中找到的那样的视频供稿.您可以想象一个ListView,您可以在其中滚动浏览一些视频(5-25秒).

视频存储在Google Cloud Platform中.

目前,可以理解的是,包含12个以上甚至9个(在某些内存较低的设备上)的feed导致该应用崩溃.

现在,我还是一个业余爱好者(几乎没有将GCP连接到Flutter,然后将其连接到:p),我正在努力寻找一种解决方案,以便能够尽可能平滑地滚动视频源.我当时在想带有可见性检测器的旋转木马,但不确定如何重新加载已处理过的视频.我的视频播放器是"Video_player"包.

我乐于助人,感谢您的帮助!

谢谢,M

解决方案

您可以在
下复制粘贴运行完整代码您可以使用软件包

完整代码

  import'package:flutter/material.dart';导入'package:inview_notifier_list/inview_notifier_list.dart';导入'package:video_player/video_player.dart';VideoWidget类扩展了StatefulWidget {最终的字符串URL;最后的布尔戏;const VideoWidget({Key key,@required this.url,@required this.play}):super(key:键);@override_VideoWidgetState createState()=>_VideoWidgetState();}类_VideoWidgetState扩展了State< VideoWidget>{VideoPlayerController _controller;Future< void>_initializeVideoPlayerFuture;@override无效的initState(){super.initState();_controller = VideoPlayerController.network(widget.url);_initializeVideoPlayerFuture = _controller.initialize().then((_){//确保在初始化视频后,甚至在按下播放按钮之前,都显示第一帧.setState((){});});如果(widget.play){_controller.play();_controller.setLooping(true);}}@overridevoid didUpdateWidget(VideoWidget oldWidget){如果(oldWidget.play!= widget.play){如果(widget.play){_controller.play();_controller.setLooping(true);} 别的 {_controller.pause();}}super.didUpdateWidget(oldWidget);}@override无效dispose(){_controller.dispose();super.dispose();}@override窗口小部件build(BuildContext context){返回FutureBuilder(未来:_initializeVideoPlayerFuture,生成器:(上下文,快照){如果(snapshot.connectionState == ConnectionState.done){返回VideoPlayer(_controller);} 别的 {退货中心(子级:CircularProgressIndicator(),);}},);}}VideoList类扩展了StatelessWidget {@override窗口小部件build(BuildContext context){返回堆栈(适合:StackFit.expand,子代:< Widget> [InViewNotifierList(scrollDirection:Axis.vertical,initialInViewIds:['0'],isInViewPortCondition:(double deltaTop,double deltaBottom,double viewPortDimension){返回deltaTop<(0.5 * viewPortDimension)&&底部>(0.5 * viewPortDimension);},子代:List.generate(30岁(指数) {返回容器(宽度:double.infinity,高度:300.0,对齐方式:Alignment.center,边距:EdgeInsets.symmetric(垂直:50.0),子级:LayoutBuilder(生成器:(BuildContext上下文,BoxConstraints约束){最终的InViewState inViewState =InViewNotifierList.of(context);inViewState.addContext(context:上下文,id:'$ index');返回AnimatedBuilder(动画:inViewState,生成器:(BuildContext上下文,小部件子项){返回VideoWidget(播放:inViewState.inView('$ index'),网址:'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');},);},),);},),),对齐(对齐方式:Alignment.center,子代:集装箱(高度:1.0,颜色:Colors.redAccent,),)],);}}void main(){runApp(MyApp());}MyApp类扩展了StatelessWidget {@override窗口小部件build(BuildContext context){返回MaterialApp(标题:"Flutter演示",主题:ThemeData(primarySwatch:Colors.blue,),主页:MyHomePage(标题:"Flutter演示首页"),);}}类MyHomePage扩展了StatefulWidget {MyHomePage({Key key,this.title}):超级(key:key);最终的字符串标题;@override_MyHomePageState createState()=>_MyHomePageState();}类_MyHomePageState扩展State< MyHomePage>{@override窗口小部件build(BuildContext context){返回脚手架(appBar:AppBar(标题:文本(widget.title),),身体:中心(子:列(mainAxisAlignment:MainAxisAlignment.center,子代:< Widget> [Expanded(child:VideoList()),],),),);}} 

I'm building an app in flutter that contains a Video Feed like the one found in TikTok. You can imagine a ListView where you can scroll through some videos (5-25seconds).

The videos are stored in Google Cloud Platform.

Currently, feed that contains more than 12 or even 9(on some devices with lower memories) is causing the app to crash, understandably.

Now, being an amateur myself, (barely connecting GCP to flutter and connecting it :p), I'm struggling to find a solution to be able to scroll through a feed of videos as smooth as possible. I was thinking something like a Carousel with a visibility detector, but I'm not sure how I can reload a video that has been disposed. My video player is "Video_player" package.

I'm open to anything, and appreciate the help!

Thanks, M

解决方案

You can copy paste run full code below
You can use package https://pub.dev/packages/inview_notifier_list
Example code will auto play video when video is on screen within a provided area
code snippet

InViewNotifierList(
          scrollDirection: Axis.vertical,
          initialInViewIds: ['0'],
          isInViewPortCondition:
              (double deltaTop, double deltaBottom, double viewPortDimension) {
            return deltaTop < (0.5 * viewPortDimension) &&
                deltaBottom > (0.5 * viewPortDimension);
          },
          children: List.generate(
            30,
            (index) {
              return Container(
                width: double.infinity,
                height: 300.0,
                alignment: Alignment.center,
                margin: EdgeInsets.symmetric(vertical: 50.0),
                child: LayoutBuilder(
                  builder: (BuildContext context, BoxConstraints constraints) {
                    final InViewState inViewState =
                        InViewNotifierList.of(context);

                    inViewState.addContext(context: context, id: '$index');

                    return AnimatedBuilder(
                      animation: inViewState,
                      builder: (BuildContext context, Widget child) {
                        return VideoWidget(
                            play: inViewState.inView('$index'),
                            url:
                                'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');
                      },

working demo

full code

import 'package:flutter/material.dart';
import 'package:inview_notifier_list/inview_notifier_list.dart';
import 'package:video_player/video_player.dart';

class VideoWidget extends StatefulWidget {
  final String url;
  final bool play;

  const VideoWidget({Key key, @required this.url, @required this.play})
      : super(key: key);
  @override
  _VideoWidgetState createState() => _VideoWidgetState();
}

class _VideoWidgetState extends State<VideoWidget> {
  VideoPlayerController _controller;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(widget.url);
    _initializeVideoPlayerFuture = _controller.initialize().then((_) {
      // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
      setState(() {});
    });

    if (widget.play) {
      _controller.play();
      _controller.setLooping(true);
    }
  }

  @override
  void didUpdateWidget(VideoWidget oldWidget) {
    if (oldWidget.play != widget.play) {
      if (widget.play) {
        _controller.play();
        _controller.setLooping(true);
      } else {
        _controller.pause();
      }
    }
    super.didUpdateWidget(oldWidget);
  }

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

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _initializeVideoPlayerFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return VideoPlayer(_controller);
        } else {
          return Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    );
  }
}

class VideoList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Stack(
      fit: StackFit.expand,
      children: <Widget>[
        InViewNotifierList(
          scrollDirection: Axis.vertical,
          initialInViewIds: ['0'],
          isInViewPortCondition:
              (double deltaTop, double deltaBottom, double viewPortDimension) {
            return deltaTop < (0.5 * viewPortDimension) &&
                deltaBottom > (0.5 * viewPortDimension);
          },
          children: List.generate(
            30,
            (index) {
              return Container(
                width: double.infinity,
                height: 300.0,
                alignment: Alignment.center,
                margin: EdgeInsets.symmetric(vertical: 50.0),
                child: LayoutBuilder(
                  builder: (BuildContext context, BoxConstraints constraints) {
                    final InViewState inViewState =
                        InViewNotifierList.of(context);

                    inViewState.addContext(context: context, id: '$index');

                    return AnimatedBuilder(
                      animation: inViewState,
                      builder: (BuildContext context, Widget child) {
                        return VideoWidget(
                            play: inViewState.inView('$index'),
                            url:
                                'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');
                      },
                    );
                  },
                ),
              );
            },
          ),
        ),
        Align(
          alignment: Alignment.center,
          child: Container(
            height: 1.0,
            color: Colors.redAccent,
          ),
        )
      ],
    );
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Expanded(child: VideoList()),
          ],
        ),
      ),
    );
  }
}

这篇关于在Flutter中实现视频供稿的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆