Flutter Web桌面端DraggableScrollableSheet滚动异常问题求解
问题原因
这是Flutter Web桌面端的已知框架行为,并非你遗漏了配置项。鼠标滚轮事件的默认处理逻辑和触控滑动事件不同:触控滑动事件会在滚动到Scrollable边界时冒泡到父级可滚动组件,而鼠标滚轮事件默认仅由当前命中的Scrollable消费,滚动到边界后不会传递给外层的DraggableScrollableSheet,因此无法触发面板的高度调整。
解决方案
你可以通过手动监听滚轮事件、同步偏移到DraggableScrollableSheet控制器的方式修复该问题,完整修改后的核心代码如下:
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Hello World', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { final String title; const MyHomePage({super.key, this.title = "Home Page"}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { // 声明DraggableScrollable控制器 final DraggableScrollableController _sheetController = DraggableScrollableController(); @override void dispose() { _sheetController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: const Center( child: Text( 'Hello, World!', ), ), floatingActionButton: FloatingActionButton( onPressed: () => showModalBottomSheet( context: context, isScrollControlled: true, builder: (_) => DraggableScrollableSheet( controller: _sheetController, expand: false, builder: (_, ScrollController scrollController) { // 用Listener监听滚轮事件 return Listener( onPointerSignal: (signal) { if (signal is PointerScrollEvent) { final currentSize = _sheetController.size; final scrollDelta = signal.scrollDelta.dy / MediaQuery.of(context).size.height; // 计算新的尺寸,限制在0~1区间 final newSize = (currentSize - scrollDelta).clamp(0.0, 1.0); // 列表未到边界时不处理滚轮,交给列表自身滚动 if (scrollController.position.atEdge) { final isAtTop = scrollController.position.pixels == 0; // 列表在顶部时,向上滚动滚轮(scrollDelta为负)需要扩大面板 if (isAtTop && scrollDelta.isNegative) { _sheetController.jumpTo(newSize); } // 列表在底部时,向下滚动滚轮(scrollDelta为正)需要缩小面板 else if (!isAtTop && scrollDelta.isPositive) { _sheetController.jumpTo(newSize); } } // 面板已经到最大/最小尺寸时,直接处理滚轮滚动列表 else if (currentSize <= 0.5 && scrollDelta.isPositive) { return; } else if (currentSize >= 1 && scrollDelta.isNegative) { return; } } }, child: ListView( controller: scrollController, physics: const ClampingScrollPhysics(), children: [for (var i = 0; i < 250; i++) Text("Item: $i")], ), ); }, ), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20))), ), tooltip: "Open Sheet!", child: const Icon(Icons.add), ), ); } }
修改后即可实现桌面端和移动端一致的联动滚动效果:列表滚动到顶部后继续向上滚动滚轮即可展开面板到全屏,滚动到底部后继续向下滚动滚轮即可收起面板。
内容的提问来源于stack exchange,提问作者pseusys
相关产品推荐
相关产品推荐

