You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止ReorderableListView拖动时覆盖AppBar及BottomNavigationBar?

解决ReorderableListView拖拽项覆盖AppBar/BottomNavigationBar的问题

默认情况下,ReorderableListView的拖拽项会全屏悬浮,很容易覆盖顶部AppBar或底部BottomNavigationBar。我们可以通过**自定义拖拽代理组件(proxyDecorator)**约束拖拽元素的显示区域,让它只在Scaffold的body范围内活动,就能解决这个问题。

修改后的完整代码

import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: CustomList()));

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

  @override
  State<CustomList> createState() => _CustomListState();
}

class _CustomListState extends State<CustomList> {
  final List<int> _items = List<int>.generate(5, (int index) => index);

  @override
  Widget build(BuildContext context) {
    // 计算顶部AppBar+状态栏的总高度
    final topBarHeight = AppBar().preferredSize.height + MediaQuery.of(context).padding.top;
    // 底部导航栏高度
    final bottomBarHeight = kBottomNavigationBarHeight;
    // body区域的可用高度
    final bodyAvailableHeight = MediaQuery.of(context).size.height - topBarHeight - bottomBarHeight;

    return Scaffold(
      appBar: AppBar(title: const Text('Custom List')),
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
        ],
      ),
      body: ReorderableListView(
        padding: const EdgeInsets.symmetric(horizontal: 40),
        // 自定义拖拽代理组件,限制显示区域
        proxyDecorator: (Widget child, int index, Animation<double> animation) {
          return AnimatedBuilder(
            animation: animation,
            builder: (context, child) {
              return ClipRect(
                child: Container(
                  // 留出顶部和底部栏的高度,避免覆盖
                  margin: EdgeInsets.only(top: topBarHeight, bottom: bottomBarHeight),
                  // 限制拖拽项最大高度为body区域高度
                  constraints: BoxConstraints(maxHeight: bodyAvailableHeight),
                  child: child,
                ),
              );
            },
            child: child,
          );
        },
        children: <Widget>[
          for (int index = 0; index < _items.length; index += 1)
            ListTile(
              key: Key('$index'),
              title: Text('Item ${_items[index]}'),
            ),
        ],
        onReorder: (int oldIndex, int newIndex) {
          setState(() {
            if (oldIndex < newIndex) {
              newIndex -= 1;
            }
            final int item = _items.removeAt(oldIndex);
            _items.insert(newIndex, item);
          });
        },
      ),
    );
  }
}

关键说明

  1. 计算区域高度:先算出顶部AppBar+状态栏的总高度、底部导航栏高度,从而确定body的可用范围。
  2. 自定义拖拽代理:通过proxyDecorator替换默认的悬浮拖拽组件,用Container的margin避开顶部和底部栏,再用constraints限制拖拽项最大高度,确保它只在body区域内活动。
  3. 裁剪溢出内容:ClipRect可以彻底裁剪掉可能超出范围的部分,避免视觉穿透。

修改后,拖拽列表项时就只会在body区域内移动,不会再覆盖AppBar和BottomNavigationBar了。

内容的提问来源于stack exchange,提问作者Kyuberi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 02:09:13