Mouse scroll stuck while cursor is on top of youtube_player_iframe

2.5k Views Asked by At

Mouse scroll stuck on top of video. I'm using youtube_player_iframe. Also, I don't want to rebuild the iframe widget. I tried to wrap it with pointer_interceptor but it didn't solve the problem. My first priority is to solve the scroll issue and avoid rebuilding the widget on scrolling. Wrapping everything on SingleChildScrollView is not a good practice.

  • I don't want to use YouTube API like this package
  • Need to implemented flutter-web

if you have an alternative way to handle it, feel free to share. Thanks

check this output video

Test widget

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:sliver_tools/sliver_tools.dart';

import 'package:youtube_player_iframe/youtube_player_iframe.dart';

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

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

class _YoutubeVideoAdTestScreen2State extends State<YoutubeVideoAdTestScreen2> {
  YoutubePlayerController _controller = YoutubePlayerController(
    initialVideoId: '1oF3pI5umck',
    params: YoutubePlayerParams(
      // Defining custom playlist
      startAt: Duration(seconds: 30),
      showControls: true,
      showFullscreenButton: true,
    ),
  );

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          MultiSliver(
            children: [
              ...List.generate(
                4,
                (index) => Container(
                  color: index % 2 == 0 ? Colors.amber : Colors.cyanAccent,
                  height: index * 50 + 100,
                ),
              ).toList(),
              SliverToBoxAdapter(
                child: YoutubePlayerIFrame(
                  gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
                  controller: _controller,
                  aspectRatio: 16 / 9,
                ),
              ),
              ...List.generate(
                4,
                (index) => Container(
                  color: index % 2 == 0 ? Colors.amber : Colors.cyanAccent,
                  height: index * 50 + 100,
                ),
              ).toList(),
            ],
          ),
        ],
      ),
    );
  }
}

1

There are 1 best solutions below

1
On

The Problem with embedding HTML elements in your Flutter App is, that these are rendered differently. The dart api provides this information about iframes and their pointer events:

Due to security restrictions with cross-origin iframe elements, Flutter cannot dispatch pointer events to an HTML view. If an iframe is the target of an event, the window containing the is not notified of the event. In particular, this means that any pointer events which land on an iframe will not be seen by Flutter, and so the HTML view cannot participate in gesture detection with other widgets.

There is no ideal solution to this, either losing the ability to scroll when hovering the iframe, or to lose the ability to interact with the iframe, but still scroll over it.

The idea is simple: Wrap another AspectRatio in a PointerInterceptor, inside a Stack, so that the scrolling behaviour is still provided, but you sadly cannot interact with the iframe any more.

.....
SliverToBoxAdapter(
  child: Stack(
    children: [
      YoutubePlayerIFrame(
        gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
        controller: _controller,
        aspectRatio: 16 / 9,
      ),
      PointerInterceptor(
        child: AspectRatio(
          aspectRatio: 16 / 9,
        ),
      ),
    ],
  ),
),
......

There are surely different ways to implement this, butI found this to be the easiest if you just want to scroll over the iframe. The player can still be controlled via its _controller, so play(), stop() etc. still seem to work.

EDIT:
The PointerInterceptor is a pub.dev package: https://pub.dev/packages/pointer_interceptor