Create a Scaffold widget with a persistent bottom sheet (bottomSheet) wrapped in a DraggableScrollableSheet.
Assign a DraggableScrollableController to DraggableScrollableSheet to allow programmatic resizing of the sheet.
Note that the default initialChildSize of DraggableScrollableSheet is 0.5. Or assign a custom initialChildSize.
Define a button/widget that when pressed, resizes the sheet programatically to any size lesser than initialChildSize. Either of the jumpTo or animateTo method of DraggableSrollableController can be used.
Resize the sheet (either by dragging manually or programmatically with another button) to any size greater than the initialChildSize.
Resize the sheet programmatically using the button defined above when the sheet is still at a size greater than initialChildSize.
(See the code sample below for a minimal, reproducible and fully-working example.)
Expected results
When the button is pressed, the DraggableScrollableSheet should resize to the correct size.
Actual results
When the button is pressed, the sheet resizes to initialChildSize instead of the specified size. This only happens when the sheet is resized using the controller to a size lesser than the initialChildSize and when the sheet's current size is greater than initialChildSize.
Cause
After some debugging, it appears that the issue is arising because a NotificationListener in Scaffold._maybeBuildPersistentBottomSheet is calling DraggableScrollableActuator.reset(context), causing the sheet to resize to its initial size. The notification listener is a local function in _maybeBuildPersistentBottomSheet called persistentBottomSheetExtentChanged.
This listener calls _persistentSheetHistoryEntry.remove() which triggers the LocalHistoryEntry's onRemove listener (defined in the same function) which in turn calls DraggableScrollableActuator.reset(context).
Code sample
Code sample
```dart
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 Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorSchemeSeed: Colors.blue,
),
home: const MyHomePage(title: 'DraggableScrollableSheet Resize Issue'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
super.key,
required this.title,
});
@override
State createState() => _MyHomePageState();
}
const _maxSheetSize = 0.9;
const _initialSheetSize = 0.4;
const _minSheetSize = 0.2;
class _MyHomePageState extends State {
final _controller = DraggableScrollableController();
bool _isResizing = false;
Future _resizeSheet(double size) async {
setState(() => _isResizing = true);
await _controller.animateTo(
size,
duration: Durations.medium1,
curve: Curves.linear,
);
setState(() => _isResizing = false);
}
@override
Widget build(BuildContext context) {
final ThemeData(
:colorScheme,
:textTheme,
) = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
constraints: BoxConstraints.expand(),
color: colorScheme.inversePrimary,
child: Center(
child: Text(
'Resize the sheet to a size greater '
'than ${_initialSheetSize} and hit "Min".',
style: textTheme.titleLarge,
),
),
),
bottomSheet: DraggableScrollableSheet(
expand: false,
initialChildSize: _initialSheetSize,
maxChildSize: _maxSheetSize,
minChildSize: _minSheetSize,
controller: _controller,
builder: (context, scrollController) => ListView(
padding: EdgeInsets.all(32.0),
controller: scrollController,
children: [
ListenableBuilder(
listenable: _controller,
builder: (context, _) => Text(
'Current Size: ${_controller.size}',
style: textTheme.displaySmall,
),
),
Text('Is Resizing: ${_isResizing}'),
const SizedBox(height: 16.0),
Wrap(
alignment: WrapAlignment.spaceBetween,
children: [
FilledButton(
child: Text('Max'),
onPressed: () => _resizeSheet(_maxSheetSize),
),
FilledButton(
child: Text('Initial'),
onPressed: () => _resizeSheet(_initialSheetSize),
),
FilledButton(
child: Text('Min'),
onPressed: () {
String message = _controller.size > _initialSheetSize
? 'Sheet should resize to ${_minSheetSize} but watch it resize to ${_initialSheetSize}.'
: 'Sheet size is initial size or smaller, so sheet will be correctly resized to ${_minSheetSize}. '
'Resize the sheet to a size greater than ${_initialSheetSize} to trigger the issue.';
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
message,
),
behavior: SnackBarBehavior.floating,
),
);
_resizeSheet(_minSheetSize);
})
],
),
],
),
),
);
}
}
```
Screenshots or Video
Screenshots / Video demonstration
Logs
Logs
Flutter Doctor output
Doctor output
The example is reproducible on DartPad with Dart 3.5.0 and Flutter 3.24.0.
Reproducible using the code and steps provided above.
flutter doctor -v
```
[!] Flutter (Channel stable, 3.24.1, on macOS 14.6.1 23G93 darwin-arm64, locale en-US)
• Flutter version 3.24.1 on channel stable at /Users/deanli/dev/stable
! The flutter binary is not on your path. Consider adding /Users/deanli/dev/stable/bin to your path.
! The dart binary is not on your path. Consider adding /Users/deanli/dev/stable/bin to your path.
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 5874a72aa4 (6 days ago), 2024-08-20 16:46:00 -0500
• Engine revision c9b9d5780d
• Dart version 3.5.1
• DevTools version 2.37.2
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.
```
```
[!] Flutter (Channel master, 3.25.0-1.0.pre.131, on macOS 14.6.1 23G93 darwin-arm64, locale en-US)
• Flutter version 3.25.0-1.0.pre.131 on channel master at /Users/deanli/dev/master
! The flutter binary is not on your path. Consider adding /Users/deanli/dev/master/bin to your path.
! The dart binary is not on your path. Consider adding /Users/deanli/dev/master/bin to your path.
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision a7eaca934d (6 hours ago), 2024-08-26 04:33:30 +0000
• Engine revision 365b0c70fa
• Dart version 3.6.0 (build 3.6.0-175.0.dev)
• DevTools version 2.39.0-dev.15
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.
```
Steps to reproduce
Scaffold
widget with a persistent bottom sheet (bottomSheet
) wrapped in aDraggableScrollableSheet
.DraggableScrollableController
toDraggableScrollableSheet
to allow programmatic resizing of the sheet.initialChildSize
ofDraggableScrollableSheet
is0.5
. Or assign a custominitialChildSize
.initialChildSize
. Either of thejumpTo
oranimateTo
method ofDraggableSrollableController
can be used.initialChildSize
.initialChildSize
.(See the code sample below for a minimal, reproducible and fully-working example.)
Expected results
When the button is pressed, the
DraggableScrollableSheet
should resize to the correct size.Actual results
When the button is pressed, the sheet resizes to
initialChildSize
instead of the specified size. This only happens when the sheet is resized using the controller to a size lesser than theinitialChildSize
and when the sheet's current size is greater thaninitialChildSize
.Cause
After some debugging, it appears that the issue is arising because a
NotificationListener
inScaffold._maybeBuildPersistentBottomSheet
is callingDraggableScrollableActuator.reset(context)
, causing the sheet to resize to its initial size. The notification listener is a local function in_maybeBuildPersistentBottomSheet
calledpersistentBottomSheetExtentChanged
.This listener calls
_persistentSheetHistoryEntry.remove()
which triggers theLocalHistoryEntry
'sonRemove
listener (defined in the same function) which in turn callsDraggableScrollableActuator.reset(context)
.Code sample
Code sample
```dart 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 Demo', debugShowCheckedModeBanner: false, theme: ThemeData( colorSchemeSeed: Colors.blue, ), home: const MyHomePage(title: 'DraggableScrollableSheet Resize Issue'), ); } } class MyHomePage extends StatefulWidget { final String title; const MyHomePage({ super.key, required this.title, }); @override StateScreenshots or Video
Screenshots / Video demonstration
Logs
Logs
Flutter Doctor output
Doctor output
The example is reproducible on DartPad with Dart 3.5.0 and Flutter 3.24.0.