【问题标题】:How to display video from path_provider in flutter?如何在颤动中显示来自 path_provider 的视频?
【发布时间】:2019-11-26 07:52:47
【问题描述】:

颤动: 如何从path_provider的位置显示video_player的视频?

【问题讨论】:

    标签: flutter flutter-dependencies


    【解决方案1】:

    您可以在下面复制粘贴运行完整代码
    在演示中,我使用getApplicationDocumentsDirectory。您可以打印完整路径以检查
    确保您的文件位于
    /data/user/0/your_proejct_name/app_flutter/Movies/2019-11-08.mp4

    代码sn-p

    Future<String> load_path_video() async {
        loading = true;
        final Directory extDir = await getApplicationDocumentsDirectory();
    
        setState(() {
          dirPath = '${extDir.path}/Movies/2019-11-08.mp4';
          print(dirPath);
          loading = false;
          // if I print ($dirPath) I have /data/user/0/com.XXXXX.flutter_video_test/app_flutter/Movies/2019-11-08.mp4
        });
      }
    
    Container(
                padding: const EdgeInsets.all(20),
                child: loading
                    ? CircularProgressIndicator()
                    : NetworkPlayerLifeCycle(
                        '$dirPath', // with the String dirPath I have error but if I use the same path but write like this  /data/user/0/com.XXXXX.flutter_video_test/app_flutter/Movies/2019-11-08.mp4 it's ok ... why ?
                        (BuildContext context, VideoPlayerController controller) =>
                            AspectRatioVideo(controller)),
              ),
    

    工作演示

    完整代码

    import 'package:flutter/material.dart';
    import 'package:path_provider/path_provider.dart';
    import 'dart:io';
    import 'package:video_player/video_player.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            // This is the theme of your application.
            //
            // Try running your application with "flutter run". You'll see the
            // application has a blue toolbar. Then, without quitting the app, try
            // changing the primarySwatch below to Colors.green and then invoke
            // "hot reload" (press "r" in the console where you ran "flutter run",
            // or simply save your changes to "hot reload" in a Flutter IDE).
            // Notice that the counter didn't reset back to zero; the application
            // is not restarted.
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      // This widget is the home page of your application. It is stateful, meaning
      // that it has a State object (defined below) that contains fields that affect
      // how it looks.
    
      // This class is the configuration for the state. It holds the values (in this
      // case the title) provided by the parent (in this case the App widget) and
      // used by the build method of the State. Fields in a Widget subclass are
      // always marked "final".
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
      String dirPath;
      bool loading = false;
    
      Future<String> load_path_video() async {
        loading = true;
        final Directory extDir = await getApplicationDocumentsDirectory();
    
        setState(() {
          dirPath = '${extDir.path}/Movies/2019-11-08.mp4';
          print(dirPath);
          loading = false;
          // if I print ($dirPath) I have /data/user/0/com.XXXXX.flutter_video_test/app_flutter/Movies/2019-11-08.mp4
        });
      }
    
      void _incrementCounter() {
        setState(() {
          // This call to setState tells the Flutter framework that something has
          // changed in this State, which causes it to rerun the build method below
          // so that the display can reflect the updated values. If we changed
          // _counter without calling setState(), then the build method would not be
          // called again, and so nothing would appear to happen.
          _counter++;
        });
      }
    
      @override
      void initState() {
        // TODO: implement initState
        load_path_video();
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        // This method is rerun every time setState is called, for instance as done
        // by the _incrementCounter method above.
        //
        // The Flutter framework has been optimized to make rerunning build methods
        // fast, so that you can just rebuild anything that needs updating rather
        // than having to individually change instances of widgets.
        return Scaffold(
          body: ListView(
            children: <Widget>[
              Container(
                padding: const EdgeInsets.all(20),
                child: loading
                    ? CircularProgressIndicator()
                    : NetworkPlayerLifeCycle(
                        '$dirPath', // with the String dirPath I have error but if I use the same path but write like this  /data/user/0/com.XXXXX.flutter_video_test/app_flutter/Movies/2019-11-08.mp4 it's ok ... why ?
                        (BuildContext context, VideoPlayerController controller) =>
                            AspectRatioVideo(controller)),
              ),
            ],
          ),
        );
      }
    }
    
    class VideoPlayPause extends StatefulWidget {
      VideoPlayPause(this.controller);
    
      final VideoPlayerController controller;
    
      @override
      State createState() {
        return _VideoPlayPauseState();
      }
    }
    
    class _VideoPlayPauseState extends State<VideoPlayPause> {
      _VideoPlayPauseState() {
        listener = () {
          setState(() {});
        };
      }
    
      FadeAnimation imageFadeAnim =
          FadeAnimation(child: const Icon(Icons.play_arrow, size: 100.0));
      VoidCallback listener;
    
      VideoPlayerController get controller => widget.controller;
    
      @override
      void initState() {
        super.initState();
        controller.addListener(listener);
        controller.setVolume(1.0);
        controller.play();
      }
    
      @override
      void deactivate() {
        controller.setVolume(0.0);
        controller.removeListener(listener);
        super.deactivate();
      }
    
      @override
      Widget build(BuildContext context) {
        final List<Widget> children = <Widget>[
          GestureDetector(
            child: VideoPlayer(controller),
            onTap: () {
              if (!controller.value.initialized) {
                return;
              }
              if (controller.value.isPlaying) {
                imageFadeAnim =
                    FadeAnimation(child: const Icon(Icons.pause, size: 100.0));
                controller.pause();
              } else {
                imageFadeAnim =
                    FadeAnimation(child: const Icon(Icons.play_arrow, size: 100.0));
                controller.play();
              }
            },
          ),
          Align(
            alignment: Alignment.bottomCenter,
            child: VideoProgressIndicator(
              controller,
              allowScrubbing: true,
            ),
          ),
          Center(child: imageFadeAnim),
          Center(
              child: controller.value.isBuffering
                  ? const CircularProgressIndicator()
                  : null),
        ];
    
        return Stack(
          fit: StackFit.passthrough,
          children: children,
        );
      }
    }
    
    class FadeAnimation extends StatefulWidget {
      FadeAnimation(
          {this.child, this.duration = const Duration(milliseconds: 500)});
    
      final Widget child;
      final Duration duration;
    
      @override
      _FadeAnimationState createState() => _FadeAnimationState();
    }
    
    class _FadeAnimationState extends State<FadeAnimation>
        with SingleTickerProviderStateMixin {
      AnimationController animationController;
    
      @override
      void initState() {
        super.initState();
        animationController =
            AnimationController(duration: widget.duration, vsync: this);
        animationController.addListener(() {
          if (mounted) {
            setState(() {});
          }
        });
        animationController.forward(from: 0.0);
      }
    
      @override
      void deactivate() {
        animationController.stop();
        super.deactivate();
      }
    
      @override
      void didUpdateWidget(FadeAnimation oldWidget) {
        super.didUpdateWidget(oldWidget);
        if (oldWidget.child != widget.child) {
          animationController.forward(from: 0.0);
        }
      }
    
      @override
      void dispose() {
        animationController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return animationController.isAnimating
            ? Opacity(
                opacity: 1.0 - animationController.value,
                child: widget.child,
              )
            : Container();
      }
    }
    
    typedef Widget VideoWidgetBuilder(
        BuildContext context, VideoPlayerController controller);
    
    abstract class PlayerLifeCycle extends StatefulWidget {
      PlayerLifeCycle(this.dataSource, this.childBuilder);
    
      final VideoWidgetBuilder childBuilder;
      final String dataSource;
    }
    
    /// A widget connecting its life cycle to a [VideoPlayerController] using
    /// a data source from the network.
    class NetworkPlayerLifeCycle extends PlayerLifeCycle {
      NetworkPlayerLifeCycle(String dataSource, VideoWidgetBuilder childBuilder)
          : super(dataSource, childBuilder);
    
      @override
      _NetworkPlayerLifeCycleState createState() => _NetworkPlayerLifeCycleState();
    }
    
    /// A widget connecting its life cycle to a [VideoPlayerController] using
    /// an asset as data source
    class AssetPlayerLifeCycle extends PlayerLifeCycle {
      AssetPlayerLifeCycle(String dataSource, VideoWidgetBuilder childBuilder)
          : super(dataSource, childBuilder);
    
      @override
      _AssetPlayerLifeCycleState createState() => _AssetPlayerLifeCycleState();
    }
    
    abstract class _PlayerLifeCycleState extends State<PlayerLifeCycle> {
      VideoPlayerController controller;
    
      @override
    
      /// Subclasses should implement [createVideoPlayerController], which is used
      /// by this method.
      void initState() {
        super.initState();
        controller = createVideoPlayerController();
        controller.addListener(() {
          if (controller.value.hasError) {
            print(controller.value.errorDescription);
          }
        });
        controller.initialize();
        controller.setLooping(true);
        controller.play();
      }
    
      @override
      void deactivate() {
        super.deactivate();
      }
    
      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return widget.childBuilder(context, controller);
      }
    
      VideoPlayerController createVideoPlayerController();
    }
    
    class _NetworkPlayerLifeCycleState extends _PlayerLifeCycleState {
      @override
      VideoPlayerController createVideoPlayerController() {
        return VideoPlayerController.network(widget.dataSource);
      }
    }
    
    class _AssetPlayerLifeCycleState extends _PlayerLifeCycleState {
      @override
      VideoPlayerController createVideoPlayerController() {
        return VideoPlayerController.asset(widget.dataSource);
      }
    }
    
    /// A filler card to show the video in a list of scrolling contents.
    Widget buildCard(String title) {
      return Card(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            ListTile(
              leading: const Icon(Icons.airline_seat_flat_angled),
              title: Text(title),
            ),
            // TODO(jackson): Remove when deprecation is on stable branch
            // ignore: deprecated_member_use
            ButtonTheme.bar(
              child: ButtonBar(
                children: <Widget>[
                  FlatButton(
                    child: const Text('BUY TICKETS'),
                    onPressed: () {
                      /* ... */
                    },
                  ),
                  FlatButton(
                    child: const Text('SELL TICKETS'),
                    onPressed: () {
                      /* ... */
                    },
                  ),
                ],
              ),
            ),
          ],
        ),
      );
    }
    
    class VideoInListOfCards extends StatelessWidget {
      VideoInListOfCards(this.controller);
    
      final VideoPlayerController controller;
    
      @override
      Widget build(BuildContext context) {
        return ListView(
          children: <Widget>[
            buildCard("Item a"),
            buildCard("Item b"),
            buildCard("Item c"),
            buildCard("Item d"),
            buildCard("Item e"),
            buildCard("Item f"),
            buildCard("Item g"),
            Card(
                child: Column(children: <Widget>[
              Column(
                children: <Widget>[
                  const ListTile(
                    leading: Icon(Icons.cake),
                    title: Text("Video video"),
                  ),
                  Stack(
                      alignment: FractionalOffset.bottomRight +
                          const FractionalOffset(-0.1, -0.1),
                      children: <Widget>[
                        AspectRatioVideo(controller),
                        Image.asset('assets/flutter-mark-square-64.png'),
                      ]),
                ],
              ),
            ])),
            buildCard("Item h"),
            buildCard("Item i"),
            buildCard("Item j"),
            buildCard("Item k"),
            buildCard("Item l"),
          ],
        );
      }
    }
    
    class AspectRatioVideo extends StatefulWidget {
      AspectRatioVideo(this.controller);
    
      final VideoPlayerController controller;
    
      @override
      AspectRatioVideoState createState() => AspectRatioVideoState();
    }
    
    class AspectRatioVideoState extends State<AspectRatioVideo> {
      VideoPlayerController get controller => widget.controller;
      bool initialized = false;
    
      VoidCallback listener;
    
      @override
      void initState() {
        super.initState();
        listener = () {
          if (!mounted) {
            return;
          }
          if (initialized != controller.value.initialized) {
            initialized = controller.value.initialized;
            setState(() {});
          }
        };
        controller.addListener(listener);
      }
    
      @override
      Widget build(BuildContext context) {
        if (initialized) {
          return Center(
            child: AspectRatio(
              aspectRatio: controller.value.aspectRatio,
              child: VideoPlayPause(controller),
            ),
          );
        } else {
          return Container();
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多