Search code examples
flutterlistviewscrollyoutube

I want to play first video in flutter listview.builer on scroll like youtube


I want to play the first video in flutter listview like youtube. when the user scrolls, the video on top should play on scrolling like youtube's main screen. on scrolling like a Youtube screen the video on top must play. if anyone knows how to do that in a flutter, please let me know. Youtube main Screen


Solution

  • This is my solution although I did not include the video player widget:

    NOTE: You need to consider different screen sizes while doing this and I also believe this answer can be improved. This is just demo.

    Step 1: Create your Video widget and make sure you know the total height it contains. In my case a total height of 250 pixels:

    import 'package:flutter/material.dart';
    
    class MyVideoWidget extends StatefulWidget {
      bool isPositioned;
      String videoUrl, thumbNailUrl;
      int index;
    
      MyVideoWidget({
        Key? key,
        required this.isPositioned,
        required this.index,
        required this.videoUrl,
        required this.thumbNailUrl,
      }) : super(key: key);
    
      @override
      State<MyVideoWidget> createState() => _MyVideoWidgetState();
    }
    
    class _MyVideoWidgetState extends State<MyVideoWidget> {
      @override
      Widget build(BuildContext context) {
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
                height: 200, // height --> 1
                color: widget.isPositioned ? Colors.red : Colors.black,
                child: Center(
                    child: Text(
                  widget.isPositioned ? widget.videoUrl : widget.thumbNailUrl,
                  style: const TextStyle(color: Colors.white),
                ))),
            SizedBox(height: 50 // height --> 2, 
                     child: Text("Video Name: ${widget.index}"))
          ],
        );
      }
    }
    

    Step 2: Set up your home page:

    • Check the number of video widgets that can fit into a phone screen or view port. For my case, it was only two that could fit which means 250 * 2 = 500.
    • Get the total height of the screen MediaQuery.of(context).size.height. For my case, it was 640 pixels in height.
    • Subtract the total number of video widgets that can fit in a screen from the screen height. 640 - 500 = 140.

    Another way to do the above steps is (For the sake of other phone sizes) MediaQuery.of(context).size.height / Total height of a video player widget. In my case, 640/250 = 2.56 which means only 2 video widgets. Then MediaQuery.of(context).size.height - (2 * 250) = 140 { 140 is the remaining space}.

    • Then on your VideoWidget add a bool flag (In my case isPositioned) that you can use to activate the video player once a user scrolls to position.
    • Add the following parameters to get isPositioned: _offset <= (250 * index) && _offset >= (250 * index) - 140.
    import 'package:flutter/material.dart';
    import 'video_widget.dart';
    
    class HomePage extends StatefulWidget {
      HomePage({Key? key}) : super(key: key);
    
      @override
      State<HomePage> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      List<String> _videoUrls = [
        "video_1",
        "video_2",
        "video_3",
        "video_4",
        "video_5",
        "video_6"
      ];
    
      final ScrollController _scrollController = ScrollController();
    
      double _offset = 0;
    
      @override
      void initState() {
        super.initState();
        _scrollController.addListener(_function);
      }
    
      @override
      void dispose() {
        super.dispose();
        _scrollController.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        print("Screen height:${MediaQuery.of(context).size.height} ");
    
        return Scaffold(
            appBar: AppBar(),
            extendBodyBehindAppBar: true,
            body: ListView.builder(
                itemCount: _videoUrls.length,
                addAutomaticKeepAlives: false,
                controller: _scrollController,
                itemBuilder: (ctx, index) {
                  print(
                      " $index: Offset ($_offset) is between  ${(250 * index) - 140} and  ${(250 * index)}");
    
                  return MyVideoWidget(
                    videoUrl: _videoUrls[index],
                    index: index,
                    thumbNailUrl: "thumbNail_$index",
                    isPositioned:
                        _offset <= (250 * index) && _offset >= (250 * index) - 140,
                    key: ObjectKey(_videoUrls[index]),
                  );
                }));
      }
    
      _function() {
        // The offset is mainly on the Y-axis (i.e x = 0) since it is a vertical list
        if (mounted)
          setState(() {
            _offset = _scrollController.offset;
          });
      }
    }