如何在DraggableScrollableSheet中实现自定义滚动动画?
解决DraggableScrollableSheet自定义滚动物理效果的问题
方案1:通过ScrollConfiguration注入自定义物理效果
DraggableScrollableSheet内部的拖动逻辑基于Scrollable组件,因此可以用ScrollConfiguration覆盖其默认的滚动物理,同时实现clamping和bouncing的混合效果:
ScrollConfiguration( behavior: ScrollConfiguration.of(context).copyWith( physics: const BouncingScrollPhysics(parent: ClampingScrollPhysics()), ), child: DraggableScrollableSheet( initialChildSize: 0.5, minChildSize: 0.2, maxChildSize: 0.8, builder: (context, scrollController) { return ListView.builder( controller: scrollController, itemCount: 20, itemBuilder: (context, index) => ListTile(title: Text('Item $index')), ); }, ), )
这里BouncingScrollPhysics作为父物理,会在面板拖动到边界时触发回弹效果,而ClampingScrollPhysics作为子物理,保证正常拖动时的阻尼感,刚好匹配你需要的混合效果。
方案2:自定义控制器实现边界回弹动画
如果需要更精细的动画控制,可以通过DraggableScrollableController监听面板尺寸变化,手动触发回弹动画:
final _sheetController = DraggableScrollableController(); @override void initState() { super.initState(); _sheetController.addListener(_handleSheetSizeChange); } void _handleSheetSizeChange() { // 到达最大高度时触发回弹 if (_sheetController.size >= _sheetController.maxSize) { _sheetController.animateTo( _sheetController.maxSize - 0.05, duration: const Duration(milliseconds: 120), curve: Curves.bounceOut, ).then((_) { _sheetController.animateTo( _sheetController.maxSize, duration: const Duration(milliseconds: 120), curve: Curves.bounceIn, ); }); } // 到达最小高度时同理可添加回弹逻辑 else if (_sheetController.size <= _sheetController.minSize) { _sheetController.animateTo( _sheetController.minSize + 0.05, duration: const Duration(milliseconds: 120), curve: Curves.bounceOut, ).then((_) { _sheetController.animateTo( _sheetController.minSize, duration: const Duration(milliseconds: 120), curve: Curves.bounceIn, ); }); } } @override void dispose() { _sheetController.removeListener(_handleSheetSizeChange); _sheetController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return DraggableScrollableSheet( controller: _sheetController, initialChildSize: 0.5, minChildSize: 0.2, maxChildSize: 0.8, builder: (context, scrollController) { return ListView.builder( controller: scrollController, itemCount: 20, itemBuilder: (context, index) => ListTile(title: Text('Item $index')), ); }, ); }
这种方式完全自定义边界处的动画细节,适合需要特定回弹幅度、速度的场景。
注意事项
- 方案1是最轻量化的原生解决方案,优先推荐;
- 如果是面板内部滚动元素需要物理效果,直接给内部的ScrollView(如ListView、GridView)设置
physics参数即可,无需修改DraggableScrollableSheet本身。
内容的提问来源于stack exchange,提问作者Somnath
相关产品推荐
相关产品推荐

