Search code examples
flutterdartflutter-video-player

PageView.builder reload content after navigation to the new page


I have a list of videos urls/youtube IDs and a PageView.builder. I want to load next/previous video according to position in the list. For example:

List videos = ['vid_0', 'vid_1', 'vid_2', 'vid_3', 'vid_4'] if current Playing video is vid_2, it should reload the next video or previous video of the list based on button event.

Currently when I press next or previous button, the same video is loaded but the PageView makes pages equal to the length of list. I am using youtube_video_player package.

Here is my code:

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

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

class WatchVideoLesson extends StatefulWidget {
  const WatchVideoLesson({Key? key}) : super(key: key);

  @override
  State<WatchVideoLesson> createState() => _WatchVideoLessonState();
}

class _WatchVideoLessonState extends State<WatchVideoLesson> {

  List ytIDs = ['mluJOYd17L8', 'd-RCKfVjFI4', 'xXPuaB7UpB0'];
  var playingVideo;

  final _pageController = PageController();
  late YoutubePlayerController _controller;
  bool _isPlayerReady = false;


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

  @override
  void initState() {
    _controller = YoutubePlayerController(
        initialVideoId: ytIDs.first,
        flags: const YoutubePlayerFlags(
          autoPlay: false,
        )
    );
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        resizeToAvoidBottomInset: true,
        appBar: AppBar(
          title: Text('Week'),
          backgroundColor: Colors.red,
        ),
        body:
        Column(
            children:[
              Expanded(
                child: PageView.builder(
                    physics: const NeverScrollableScrollPhysics(),
                    controller: _pageController,
                    itemCount: ytIDs.length,
                    itemBuilder: (context, index) {
                      return Column(
                        children: [
                          Container(
                            decoration: const BoxDecoration(
                              color: Colors.grey,
                            ),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.spaceAround,
                              children: [
                                ElevatedButton(style: ElevatedButton.styleFrom(
                                    backgroundColor: Colors.red),
                                    onPressed: () {
                                      _pageController.previousPage(duration: Duration(seconds: 1), curve: Curves.ease);
                                    },
                                    child: Icon(Icons.arrow_back_ios_new,)),
                                SizedBox(width: 10,),
                                Flexible(child: Text('Video Title', overflow: TextOverflow.ellipsis,)),
                                SizedBox(width: 10,),
                                ElevatedButton(style: ElevatedButton.styleFrom(
                                    backgroundColor: Colors.green),
                                    onPressed: () {
                                      _pageController.nextPage(duration: Duration(seconds: 1), curve: Curves.easeInOut);

                                    },
                                    child: Icon(Icons.arrow_forward_ios,)),
                              ],
                            ),
                          ),
                          SizedBox(height: 20,),
                          YoutubePlayer(
                            progressColors: const ProgressBarColors(
                                playedColor: Colors.red,
                                handleColor: Colors.green),
                            controller: _controller,
                            showVideoProgressIndicator: true,
                            onReady: (){
                              _isPlayerReady = true;
                            },
                          ),

                          SizedBox(height: 10,),
                        ],
                      );
                    }
                ),
              ),
            ]
        ),
      ),
    );
  }
}

Solution

  • Current snippet using the same controller on YoutubePlayer and my guess this is issue having same video. I separating the widget so that it can have different controller for PageView item.

    class WatchVideoLesson extends StatefulWidget {
      const WatchVideoLesson({Key? key}) : super(key: key);
    
      @override
      State<WatchVideoLesson> createState() => _WatchVideoLessonState();
    }
    
    class _WatchVideoLessonState extends State<WatchVideoLesson> {
      List ytIDs = ['mluJOYd17L8', 'd-RCKfVjFI4', 'xXPuaB7UpB0'];
      var playingVideo;
    
      final _pageController = PageController();
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Column(children: [
              Expanded(
                child: PageView.builder(
                    physics: const NeverScrollableScrollPhysics(),
                    controller: _pageController,
                    itemCount: ytIDs.length,
                    itemBuilder: (context, index) {
                      return Column(
                        children: [
                          Container(
                            decoration: const BoxDecoration(
                              color: Colors.grey,
                            ),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.spaceAround,
                              children: [
                                ElevatedButton(
                                    style: ElevatedButton.styleFrom(
                                        backgroundColor: Colors.red),
                                    onPressed: () {
                                      _pageController.previousPage(
                                          duration: Duration(seconds: 1),
                                          curve: Curves.ease);
                                    },
                                    child: Icon(
                                      Icons.arrow_back_ios_new,
                                    )),
                                SizedBox(
                                  width: 10,
                                ),
                                Flexible(
                                    child: Text(
                                  'Video Title',
                                  overflow: TextOverflow.ellipsis,
                                )),
                                SizedBox(
                                  width: 10,
                                ),
                                ElevatedButton(
                                    style: ElevatedButton.styleFrom(
                                        backgroundColor: Colors.green),
                                    onPressed: () {
                                      _pageController.nextPage(
                                          duration: Duration(seconds: 1),
                                          curve: Curves.easeInOut);
                                    },
                                    child: Icon(
                                      Icons.arrow_forward_ios,
                                    )),
                              ],
                            ),
                          ),
                          YTPlayer(ytIDs: ytIDs[index]),
                          SizedBox(
                            height: 20,
                          ),
                          SizedBox(
                            height: 10,
                          ),
                        ],
                      );
                    }),
              ),
            ]),
          ),
        );
      }
    }
    
    class YTPlayer extends StatefulWidget {
      final String ytIDs;
      const YTPlayer({super.key, required this.ytIDs});
    
      @override
      State<YTPlayer> createState() => _YTPlayerState();
    }
    
    class _YTPlayerState extends State<YTPlayer> {
      late YoutubePlayerController _controller;
      bool _isPlayerReady = false;
    
      @override
      void dispose() {
        _controller.dispose();
        super.dispose();
      }
    
      @override
      void initState() {
        super.initState();
        _controller = YoutubePlayerController(
            initialVideoId: widget.ytIDs,
            flags: const YoutubePlayerFlags(
              autoPlay: false,
            ));
      }
    
      @override
      Widget build(BuildContext context) {
        return YoutubePlayer(
          controller: _controller,
          progressColors: const ProgressBarColors(
              playedColor: Colors.red, handleColor: Colors.green),
          showVideoProgressIndicator: true,
          onReady: () {
            _isPlayerReady = true;
          },
        );
      }
    }