在列表视图中滚动地图时如何避免滚动列表视图

Posted

技术标签:

【中文标题】在列表视图中滚动地图时如何避免滚动列表视图【英文标题】:How to avoid scrolling listview when scrolling in map within listview 【发布时间】:2019-10-05 10:14:35 【问题描述】:

我有一个 ListView,在它的顶部有一个地图,我希望在 ListView 滚动时地图滚动到视图之外,但我也希望用户能够与地图进行交互。因此,只有当用户在其他 ListView 小部件上滚动而不是在他们在地图上滚动时才会发生滚动,然后我希望将手势直接应用于地图。 但目前,当用户在地图上滚动时,它会滚动整个 ListView。

我已经尝试过我在这里遇到的其他建议 In Flutter, how can a child widget prevent the scrolling of its scrollable parent? 我添加了GestureDetector,正如上面帖子的答案中所建议的那样,将地图容器包装在下面的示例中,但这只是阻止了在地图上滚动时 ListView 和 Map 的滚动。视频链接https://imgur.com/SeCRzUC

这是我的构建方法返回的小部件。此代码依赖于google_maps_flutter 插件。

Container(
  height: MediaQuery.of(context).size.height,
  child:
  ListView.builder(
    itemCount: 12 + 1,
    itemBuilder: (context, index) 
      if (index == 0) return GestureDetector(
        onVerticalDragUpdate: (_),
        child: Container(
          height: MediaQuery.of(context).size.height / 2,
          child: GoogleMap(initialCameraPosition: initalPosition),
        ),
      );
      else return ListTile(title: Text("$index"),);
    
  )
),

我曾希望地图会捕捉手势,但它没有,包含它的列表视图会捕捉所有。谁能建议我如何强制列表中此项目的所有手势直接传递到地图,并且在列表中的其他项目滚动时仍然让列表滚动?

【问题讨论】:

【参考方案1】:

编辑:campovski 下面的答案是更新后的答案。

Depreciated Answer:

如果您想在滚动时从屏幕上移出 GoogleMap 小部件,请使用 ListView 包装所有内容。

使用 GoogleMap 手势识别器覆盖 ListView 滚动物理。

由于 ListView 物理之间的冲突,禁用 ListView.builder 滚动物理。

首先导入依赖:

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';

构建方法:

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: ListView(
        children: <Widget>[
          SizedBox(
            height: MediaQuery.of(context).size.height / 2,
            child: GoogleMap(
              initialCameraPosition:
                  CameraPosition(target: LatLng(41, 29), zoom: 10),
              gestureRecognizers: Set()
                ..add(
                    Factory<PanGestureRecognizer>(() => PanGestureRecognizer()))
                ..add(
                  Factory<VerticalDragGestureRecognizer>(
                      () => VerticalDragGestureRecognizer()),
                )
                ..add(
                  Factory<HorizontalDragGestureRecognizer>(
                      () => HorizontalDragGestureRecognizer()),
                )
                ..add(
                  Factory<ScaleGestureRecognizer>(
                      () => ScaleGestureRecognizer()),
                ),
            ),
          ),
          ListView.builder(
            physics: const NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            itemCount: 12,
            itemBuilder: (context, index) 
              return ListTile(
                title: Text("$index"),
              );
            ,
          )
        ],
      ),
    );
  

【讨论】:

感谢您的回答!我是否说 ListView 现在根本不会滚动?抱歉,在重读我最初的帖子时,我意识到我没有明确表示如果用户在列表的任何其他部分(地图除外)滚动,我仍然希望 ListView 滚动 @diarmuid 这正是你想要的,试试看 :)【参考方案2】:

接受的答案(Eset Mehmet 的答案在撰写本文时被标记为例外)太复杂了,就我而言,它甚至不起作用!它提供从左到右的滚动、平移和缩放,但从上到下的滚动仍然滚动ListView

真正的解决方案非常简单,因为GoogleMap 默认具有这些手势检测器。您只需指定手势检测必须由GoogleMap 而不是ListView 优先。这可以通过以下方式为GoogleMap 对象提供EagerGestureRecognizer 来实现。

ListView(
  children: <Widget>[
    Text('a'),
    Text('b'),
    GoogleMap(
      ...,
      gestureRecognizers: 
        Factory<OneSequenceGestureRecognizer>(
          () => EagerGestureRecognizer(),
        ),
      ,
    ),
  ],
)

这样,GoogleMap 对象上或上方发生的所有手势都将由GoogleMap 优先处理,而不是任何其他小部件。

【讨论】:

感谢@campovski,这个 5 行解决方案对我来说非常有用。我可以在 ListView 中滚动,然后当我触摸地图时我可以在地图内滚动。 @eluong 很高兴它有帮助,这对我来说是一场噩梦,所以我决定分享我的解决方案。 @campovski 谢谢!这就是我一直在寻找的 不需要 EagerGestureRecognizer,试试这个解决方案 ***.com/questions/54280541/… 有了这个解决方案,您仍然可以使用 Pageview。急切的识别器将不允许页面浏览量滚动

以上是关于在列表视图中滚动地图时如何避免滚动列表视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在相对布局中添加固定标题和滚动视图表行?

当我在 Android 上滚动列表视图时复选框未选中

SwiftUI List 在任何视图更改时重置滚动

滚动列表视图时文本视图中的数据切换

滚动列表视图垂直和水平相同的图像

更改视图控制器时保持滚动位置