【问题标题】:How to ignore only scroll events on widget?如何仅忽略小部件上的滚动事件?
【发布时间】:2022-10-13 12:49:12
【问题描述】:

我在Html 小部件中显示iframe,在ListView.builder 中。

由于 iframe,我无法滚动页面。当我开始从它们之间的空白处拖动时,我只能滚动。

我试图用AbsorbPointerIgnorePointer 包装Html 小部件,它们正在工作,我可以滚动,但我不想完全禁用iframe 上的指针事件。因为其中一些是可点击的(例如它有一个标签栏,例如:比特币|第一张图上的以太币)

问题是,我是否可以吸收这些 iframe 的所有拖动和滚动事件,让用户正常滚动页面,同时也让他们点击 iframe?

class HubContentWidget extends StatefulWidget {
  const HubContentWidget({
    Key? key,
    required this.hub,
  }) : super(key: key);

  final HubCategory hub;

  @override
  State<HubContentWidget> createState() => _HubContentWidgetState();
}

class _HubContentWidgetState extends State<HubContentWidget> {
  late Future<List<HubItem>> _hubFuture;
  @override
  void initState() {
    _hubFuture = Service.getHubItems(uri: widget.hub.uri);
    super.initState();
  }

  bool absorbPointers = false;
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<HubItem>>(
      future: _hubFuture,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          final items = snapshot.data!;
          if (items.isEmpty) {
            return Center(child: Text('No items found'));
          }
          return ListView.builder(
            shrinkWrap: true,
            itemCount: items.length,
            itemBuilder: (context, index) {
              /// This widget takes all the pointer events 
              /// and prevents scrolling.
              return Html(
                data: items[index].content.formatted,
                navigationDelegateForIframe: (request) {
                  return NavigationDecision.navigate;
                },
              );
            },
          );
        } else {
          return CircularProgressIndicator.adaptive();
        }
      },
    );
  }
}

来自flutter_html-2.2.1 的 HTML 小部件

iframe 示例

<p><iframe title="The rise and fall of cryptocurrency" aria-label="Interactive line chart" id="datawrapper-chart-acQ2e" src="https://datawrapper.dwcdn.net/acQ2e/4/" scrolling="no" frameborder="0" style="width: 0; min-width: 100% !important; border: none;" height="450"></iframe><script type="text/javascript">!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();
</script></p>

【问题讨论】:

  • 请附上您的代码和您取得的成就
  • @mohammadesmaili 已添加代码。
  • 请添加您传递给Html 的数据示例,谢谢
  • 我尝试了单个列表视图的代码,但它没有水平滚动,而在 listviewB 中我可以垂直滚动而没有空格,我错过了什么吗?或者这个示例 iframe 是否水平滚动?
  • @mohammadesmaili 感谢您的退房。我不需要水平滚动,也没有水平滚动的代码。问题是,当我想垂直滚动页面时,每当我点击 iframe 时,iframe 都会接受所有的触摸事件并且不会让我滚动。我需要找到一个没有被 iframe 占用的空白区域来点击和滚动。

标签: flutter


【解决方案1】:

好吧,我认为这种方式可以让您滚动,希望这也适用于您,

我将构建器的scrollDirection 设置为Axis.vertical 并用SingleChildScrollView 包装Html:

ListView.builder(
        shrinkWrap: true,
        itemCount: 10,
        scrollDirection: Axis.vertical,
        itemBuilder: (context, index) {
          return SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            physics: const NeverScrollableScrollPhysics(),
            child: Html(
              data:
                  """<p><iframe title="The rise and fall of cryptocurrency" aria-label="Interactive line chart" id="datawrapper-chart-acQ2e" src="https://datawrapper.dwcdn.net/acQ2e/4/" scrolling="no" frameborder="0" style="width: 0; min-width: 100% !important; border: none;" height="450"></iframe><script type="text/javascript">!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();
            </script></p>""",
              navigationDelegateForIframe: (request) {
                return NavigationDecision.navigate;
              },
            ),
          );
        },
      ),

这个结果来自你的 iframe 示例,对我来说效果很好,结果如下:

看看这个结果,我通过点击 iframe 滚动,尝试一下,让我知道结果

【讨论】:

  • 谢谢你。你确定这有效吗?或者你能解释一下吗?我已经测试过了,没有任何改变。至于代码, Axis.vertical 无论如何都是 ListView.builder 的默认值。水平但从不滚动的 SingleChildScrollView 也没有帮助。
  • 我拍摄了屏幕记录,我点击 iframe 并移动
  • 您能告诉我您使用的是哪个 android、flutter 和 flutter_html 版本吗?你确定你有同样的错误并修复以下内容吗?也许你的版本没有同样的问题。
  • flutter_html: ^2.2.1Flutter 3.3.0,我在真实设备上测试samsung a40,也许你的颤振版本是旧的或者我的设备支持它,IDK,在我测试之前我没有你的错误,它很好,我添加了这个解决方案可能会改变你的输出
  • 是的,这是一个早期的 Flutter 2 的旧项目。我会检查它是来自 Flutter 还是真实设备。感谢您的输入。那很有帮助。另一方面,代码中的更改似乎是多余的并且没有帮助。
【解决方案2】:

我认为@mohammad esmaili 的回答应该对您的情况有所帮助。但是,如果您仍然有问题,因为使用旧的颤振或 sdk 并且不打算迁移。

您可以添加逻辑(布尔值)来打开/关闭 AbsorbPointer。 一些示例 UX 场景:

  • 添加一个按钮或开关,可以启用/禁用每个 iframe 的 AbsorbPointer
  • 当用户单击区域 1 次时,在容器/iframe 中添加逻辑,它将关闭/关闭吸收指针

【讨论】:

    【解决方案3】:

    如果需要,可以将 ListView.builder 物理属性与 NeverScrollableScrollPhysics() 一起使用 您还可以将其绑定到可以用单行确定的变量,例如;可拖动==真? NeverScrollableScrollPhysics(): AlwaysScrollableScrollPhysics

    【讨论】:

    • 我认为没有我想要 NeverScrollableScrollPhysics() 的用例。问题是,HTML 小部件正在吸收 ListView.builder 中的点击。我只能从空白处滚动,指针事件在没有阻塞的情况下进入列表:就像在两个 Html 小部件之间。我可以通过使用 AbsorbPointer 或 IgnorePointer 包装子小部件(Html)来使 ListView.builder 再次获取指针事件。但是这个解决方案使 iframe 成为非交互式的。
    猜你喜欢
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 2014-01-02
    • 2018-07-05
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2019-05-23
    相关资源
    最近更新 更多