5

I am developing an APP using Fluter. In the APP a have a list of PageViews and each PageView will load and play a video when it appears. Any PageView will stop playing the video when it disappears. Now I have a question. When I slowly slide between PageViews, there will be two PageView at the same time. Each PageView appears a part. But all the two PageView are playing video. I want to know whether I can check the current PageView totally disappears, then I stop playing the video. And when the next PageView is totally showed, it begins to play video. So it will not play videos in two PageView at the same time. Anyone can help me?

import 'package:video_player/video_player.dart';
import 'package:flutter/material.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(
        primarySwatch: Colors.blue,
      ),
      home: MultiplePage(),
    );
  }
}

class MultiplePage extends StatefulWidget {
  @override
  _MultiplePageState createState() => _MultiplePageState();
}

class _MultiplePageState extends State<MultiplePage> {
  PageController _controller;

  void scrollListener() {
    if (_controller.page == _controller.page.roundToDouble()) {
      print(_controller.page);
    }
  }

  @override
  void initState() {
    super.initState();
    _controller = PageController()..addListener(scrollListener);
  }

  @override
  Widget build(BuildContext context) {
    return PageView.builder(
      controller: _controller,
      scrollDirection: Axis.vertical,
      itemBuilder: (context, position) {
        return VideoApp();
      },
    );
  }
}

class VideoApp extends StatefulWidget {
  @override
  _VideoAppState createState() => _VideoAppState();
}

class _VideoAppState extends State<VideoApp> {
  VideoPlayerController _controller;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(
        'http://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4')
      ..initialize().then((_) {
        // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
        setState(() {
          _controller.play();
        });
      });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Demo',
      home: Scaffold(
        body: Center(
          child: _controller.value.initialized
              ? AspectRatio(
            aspectRatio: _controller.value.aspectRatio,
            child: VideoPlayer(_controller),
          )
              : Container(),
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    _controller.pause();
    _controller.dispose();
  }
}
Nature.Li
  • 345
  • 1
  • 3
  • 11

2 Answers2

12

Use PageController to check if page totally turns.

enter image description here

import 'package:video_player/video_player.dart';
import 'package:flutter/material.dart';
import 'package:sprintf/sprintf.dart';
import 'package:preload_page_view/preload_page_view.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(
        primarySwatch: Colors.blue,
      ),
      home: MultiplePage(),
    );
  }
}

class MultiplePage extends StatefulWidget {
  @override
  _MultiplePageState createState() => _MultiplePageState();
}

class _MultiplePageState extends State<MultiplePage> {
  PreloadPageController _controller;
  int current = 0;
  bool isOnPageTurning = false;

  void scrollListener() {
    if (isOnPageTurning &&
        _controller.page == _controller.page.roundToDouble()) {
      setState(() {
        current = _controller.page.toInt();
        isOnPageTurning = false;
      });
    } else if (!isOnPageTurning && current.toDouble() != _controller.page) {
      if ((current.toDouble() - _controller.page).abs() > 0.1) {
        setState(() {
          isOnPageTurning = true;
        });
      }
    }
  }

  @override
  void initState() {
    super.initState();
    _controller = PreloadPageController();
    _controller.addListener(scrollListener);
  }

  @override
  Widget build(BuildContext context) {
    return PreloadPageView.builder(
      controller: _controller,
      scrollDirection: Axis.vertical,
      preloadPagesCount: 3,
      itemBuilder: (context, pageIndex) {
        return VideoApp(
          pageIndex: pageIndex,
          currentPageIndex: current,
          isPaused: isOnPageTurning,
        );
      },
    );
  }
}

class VideoApp extends StatefulWidget {
  VideoApp({
    this.pageIndex,
    this.currentPageIndex,
    this.isPaused,
  });

  final int pageIndex;
  final int currentPageIndex;
  final bool isPaused;

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

class _VideoAppState extends State<VideoApp> {
  VideoPlayerController _controller;
  bool initialized = false;

  @override
  void initState() {
    super.initState();
    print(sprintf("init: %d", [widget.pageIndex]));
    _controller = VideoPlayerController.network(
        "http://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4")
      ..initialize().then((_) {
        setState(() {
          _controller.setLooping(true);
          initialized = true;
        });
      });
  }

  @override
  Widget build(BuildContext context) {
    if (widget.pageIndex == widget.currentPageIndex &&
        !widget.isPaused &&
        initialized) {
      _controller.play();
    } else {
      _controller.pause();
    }

    return MaterialApp(
      title: 'Video Demo',
      home: Scaffold(
        body: Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            border: Border.all(
              color: Colors.blueAccent,
            ),
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Text('is paused: ${widget.isPaused.toString()}'),
              Text('currentPageIndex: ${widget.currentPageIndex.toString()}'),
              Text('pageIndex: ${widget.pageIndex.toString()}'),
              _controller.value.initialized
                  ? AspectRatio(
                      aspectRatio: _controller.value.aspectRatio,
                      child: VideoPlayer(_controller),
                    )
                  : Container(
                      decoration: BoxDecoration(color: Colors.black),
                    ),
            ],
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    print(sprintf("dispose: %d", [widget.pageIndex]));
    super.dispose();
    _controller.dispose();
  }
}

...

If someoneelse are searching for the same answer, used packages are:

video_player: ^0.10.1+3
http: ^0.12.0+2
sprintf: ^4.0.2
preload_page_view: ^0.1.4
Kherel
  • 14,882
  • 5
  • 50
  • 80
0

You actually don't need to manually stop the video on the disappearing page.

By default the PageView will automatically disposes the page when its completely scrolled out. And it will recreate the Page when you starting the scroll.

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Player Demo',
      home: MainPage(),
    );
  }
}

class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Demo")),
      body: PageView(
        children: <Widget>[
          Page1(),
          Page1(),
          Page1(),
        ],
      ),
    );
  }
}

class Page1 extends StatefulWidget {
  Page1({Key key}) : super(key: key);

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

class _Page1State extends State<Page1> {
  VideoPlayerController _controller;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    _controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
    );
    _initializeVideoPlayerFuture = _controller.initialize();
    _controller.setLooping(true);
    _controller.play();
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: FutureBuilder(
        future: _initializeVideoPlayerFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Text("${snapshot.error}");
          } else {
            return AspectRatio(
              aspectRatio: _controller.value.aspectRatio,
              child: VideoPlayer(_controller),
            );
          }
        },
      ),
    );
  }
}
Crazy Lazy Cat
  • 13,595
  • 4
  • 30
  • 54
  • Thank you for your answer. But if you slide between two pages slowly, there will be two videos playing at the same time. How to control the next page start to play video only when the pre one totally disappears and the next page totally appears? – Nature.Li Jan 10 '20 at 02:40
  • You can use https://pub.dev/packages/visibility_detector – jennie788 Jul 02 '21 at 05:27