I'm wondering if anyone knows/found a way to make Flutters' DraggableScrollableSheet expand/collapse programmatically. I'm using Flutters latest build from their Dev channel which allows me to wrap it in a
NotificationListener<DraggableScrollableNotification>
which I can then listen to the extend of how far the sheets is expanded / collapsed. However, I'm not clear on how I would be able to collapse an expanded sheet or vice versa.
Seems in the widget src file there's a
DraggableScrollableActuator
that exposes a static .reset but I don't know/or think of a way to make that work.
Building on Pierre's answer I ended up implementing a workaround that allows me to use DraggableScrollableActuator to both collapse and expand the DraggableScrollableSheet.
You can use the setState method to change the value of initialChildSize and then use the DraggableScrollableActuator.reset method to either expand or collapse the sheet.
void toggleDraggableScrollableSheet() {
if (draggableSheetContext != null) {
setState(() {
initialExtent = isExpanded ? minExtent : maxExtent;
});
DraggableScrollableActuator.reset(draggableSheetContext);
}
}
Important thing to make this work is to provide a different Key for when the widget is collapsed and expanded. This will result in 2 instances of _DraggableScrollableSheetState - one that you will be able to reset to collapsed state and another that you will be able to reset to expanded state.
DraggableScrollableActuator(
child: DraggableScrollableSheet(
key: Key(initialExtent.toString()),
minChildSize: minExtent,
maxChildSize: maxExtent,
initialChildSize: initialExtent,
builder: draggableScrollableSheetBuilder,
),
)
Edit:
Working example:
import 'package:flutter/material.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
static const List<Color> colors = [
Colors.red,
Colors.green,
Colors.blue,
];
static const double minExtent = 0.2;
static const double maxExtent = 0.6;
bool isExpanded = false;
double initialExtent = minExtent;
BuildContext draggableSheetContext;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: _buildBody(),
),
);
}
Widget _buildBody() {
return InkWell(
onTap: _toggleDraggableScrollableSheet,
child: DraggableScrollableActuator(
child: DraggableScrollableSheet(
key: Key(initialExtent.toString()),
minChildSize: minExtent,
maxChildSize: maxExtent,
initialChildSize: initialExtent,
builder: _draggableScrollableSheetBuilder,
),
),
);
}
void _toggleDraggableScrollableSheet() {
if (draggableSheetContext != null) {
setState(() {
initialExtent = isExpanded ? minExtent : maxExtent;
isExpanded = !isExpanded;
});
DraggableScrollableActuator.reset(draggableSheetContext);
}
}
Widget _draggableScrollableSheetBuilder(
BuildContext context,
ScrollController scrollController,
) {
draggableSheetContext = context;
return SingleChildScrollView(
controller: scrollController,
child: Column(
children: colors
.map((color) => Container(
height: 200,
width: double.infinity,
color: color,
))
.toList(),
),
);
}
}
You can reset the position of the DraggableScrollableSheet to its initialChildSizeby using the DraggableScrollableActuator.
Therefore you need to have the BuildContext, which is given to you by the DraggableScrollableSheet builder-parameter.
For example, you can create a Button inside the DraggableScrollableSheetand call DraggableScrollableActuator.reset(context);
DraggableScrollableSheet(
builder: (BuildContext context, ScrollController scrollController) {
return MaterialButton(
onPressed: () {
DraggableScrollableActuator.reset(context);
},
);
},
)
If you want to reset the DraggableScrollableSheet from outside its build-function, you need to create a property of BuildContext, which can be used to save the DraggableScrollableSheet context into.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With