简体   繁体   English

在 Flutter 中实现视频馈送的最佳方法是什么?

[英]What is the best way to implement a video feed in Flutter?

I'm building an app in flutter that contains a Video Feed like the one found in TikTok.我正在 flutter 中构建一个应用程序,其中包含一个类似于 TikTok 中的视频源。 You can imagine a ListView where you can scroll through some videos (5-25seconds).您可以想象一个 ListView,您可以在其中滚动浏览一些视频(5-25 秒)。

The videos are stored in Google Cloud Platform.视频存储在 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.目前,包含超过 12 个甚至 9 个(在某些内存较低的设备上)的提要导致应用程序崩溃,这是可以理解的。

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.现在,作为一个业余爱好者,(几乎没有将 GCP 连接到 flutter 并连接它:p),我正在努力寻找一种能够尽可能流畅地滚动视频源的解决方案。 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.我在想像带有可见度检测器的 Carousel 之类的东西,但我不确定如何重新加载已处理的视频。 My video player is "Video_player" package.我的视频播放器是“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您可以使用 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()),
          ],
        ),
      ),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM