Flutter - 与子小部件交互时停止 ListView 滚动

Posted

技术标签:

【中文标题】Flutter - 与子小部件交互时停止 ListView 滚动【英文标题】:Flutter - stop ListView scrolling when interacting with child widget 【发布时间】:2019-03-03 18:47:29 【问题描述】:

我有点吃不消了。我正在开发一个 Flutter 应用程序(目前在 android Studio 的 Windows 上使用 0.8.2 版),我似乎无法解决这个实现细节。很可能它是如此简单,我错过了它,但如果有人能指出我正确的方向,我将不胜感激!

我的问题是:我创建了一个自定义颜色选择器小部件,它位于滚动 ListView 中。为了让用户与颜色选择器小部件正确交互,每当用户在选择器内拖动颜色指针时,我需要停止 ListView 滚动,但我需要在交互完成后允许 ListView 滚动(所以我不能只将物理设置为 NeverScrollableScrollPhysics)。

这里是一个屏幕截图的链接 Interface

我目前正在使用侦听器来处理颜色选择器中的交互,每当用户拖动指针时,ListView 也会滚动。我曾尝试使用 GestureDetector 但 pan DestureDetector 不会阻止 ListView 滚动。我也尝试向 GestureDetector 添加一个垂直拖动处理程序,这确实阻止了 ListView 滚动,但这样做会在指针移动之前添加一个最小拖动距离,因为 GestureDetector 试图区分平移和垂直拖动。

我会喜欢任何建议或正确方向的指针。谢谢!

【问题讨论】:

你解决了吗? 【参考方案1】:

这是一个老问题,但是当我自己也遇到同样的问题时,这里有一个技巧:

 bool _dragOverMap = false;
  GlobalKey _pointerKey = new GlobalKey();

  _checkDrag(Offset position, bool up) 
    if (!up) 
      // find your widget
      RenderBox box = _pointerKey.currentContext.findRenderObject();

      //get offset
      Offset boxOffset = box.localToGlobal(Offset.zero);

      // check if your pointerdown event is inside the widget (you could do the same for the width, in this case I just used the height)
      if (position.dy > boxOffset.dy &&
          position.dy < boxOffset.dy + box.size.height) 
        setState(() 
          _dragOverMap = true;
        );
      
     else 
      setState(() 
        _dragOverMap = false;
      );
    
  

  @override
  Widget build(BuildContext context) 

    return Scaffold(
      appBar: AppBar(

        title: Text("Scroll Test"),
      ),
      body: new Listener(
        onPointerUp: (ev) 
          _checkDrag(ev.position, true);
        ,
        onPointerDown: (ev) 
          _checkDrag(ev.position, false);
        ,
        child: ListView(
          // if dragging over your widget, disable scroll, otherwise allow scrolling
          physics:
              _dragOverMap ? NeverScrollableScrollPhysics() : ScrollPhysics(),
          children: [

            ListTile(title: Text("Tile to scroll")),
            Divider(),
              ListTile(title: Text("Tile to scroll")),
            Divider(),
              ListTile(title: Text("Tile to scroll")),
            Divider(),

            // Your widget that you want to prevent to scroll the Listview 
            Container(
              key: _pointerKey, // key for finding the widget
              height: 300,
              width: double.infinity,
              child: FlutterMap(
               // ... just as example, could be anything, in your case use the color picker widget
              ),
            ),
          ],
        ),
      ),
    );
  

对我来说很好,也许可以简化一些事情,但你明白了。

【讨论】:

【参考方案2】:

也许对你有帮助。

  bool _scroll = false;

  _toggleScroll() 
    _scroll = !_scroll;
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: ListView(
          // switch scrolling
          physics: _scroll ? NeverScrollableScrollPhysics() : ScrollPhysics(),
          children: [],
      ),
    );
  

【讨论】:

以上是关于Flutter - 与子小部件交互时停止 ListView 滚动的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 不更新子小部件

如何从 Flutter 中的子小部件调用父小部件功能

如何在 Flutter 中正确重用 Provider

如何在 AppBar 中包装子小部件以获得更大的子高度和 Flutter 中的填充

网络调用后如何修改 UI 以填充子小部件

是否可以强制对齐 Wrap 小部件中的特定子小部件?