首页 > 解决方案 > Mouse scroll stuck while cursor is on top of youtube_player_iframe

问题描述

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.

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(),
            ],
          ),
        ],
      ),
    );
  }
}

标签: flutterflutter-layoutflutter-webyoutube-player-flutter

解决方案


在 Flutter 应用程序中嵌入 HTML 元素的问题在于,这些元素的呈现方式不同。iframesdart api 提供了以下信息pointer events

由于跨域iframe元素的安全限制,Flutter无法将指针事件分派到 HTML 视图。如果 aniframe是事件的目标,则不通知包含该事件的窗口。特别是,这意味着任何落在 an 上的指针事件iframe都不会被 Flutter 看到,因此 HTML 视图无法与其他小部件一起参与手势检测

对此没有理想的解决方案,要么在悬停 时失去滚动能力,要么失去与iframe交互的能力 iframe,但仍然在其上滚动。

这个想法很简单:将另一个包装AspectRatio在 a 中PointerInterceptor,在 aStack中,这样仍然提供滚动行为,但遗憾的是你不能再与它交互了iframe

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

肯定有不同的方法来实现这一点,但我发现如果你只想滚动iframe. 播放器仍然可以通过它的_controller, so等来控制play()stop()似乎仍然可以工作。

编辑
PointerInterceptor是一个 pub.dev 包:https ://pub.dev/packages/pointer_interceptor


推荐阅读