Flutter中实现视频流的最佳方法是什么?

6

我正在使用Flutter构建一个应用程序,其中包含类似TikTok中视频Feed的功能。可以想象一下一个ListView,您可以在其中浏览一些视频(5-25秒)。

这些视频存储在Google Cloud Platform中。

目前,包含超过12个或甚至9个(在一些内存较低的设备上)视频的Feed会导致应用程序崩溃,这是可以理解的。

现在,作为一个业余爱好者,(几乎没有将GCP连接到Flutter并进行连接:p),我正在努力寻找解决方案,以尽可能流畅地滚动视频Feed。我考虑使用Carousel和VisibilityDetector,但我不确定如何重新加载已被处理的视频。我的视频播放器是“video_player”包。

我对任何建议都持开放态度,并感激您的帮助!

谢谢, M

1个回答

10

您可以复制粘贴下面的完整代码
您可以使用包https://pub.dev/packages/inview_notifier_list
示例代码将在提供的区域内自动播放视频,当视频出现在屏幕上时
代码片段:

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');
                      },

演示

在此输入图片描述

完整代码

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()),
          ],
        ),
      ),
    );
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接