Reputation: 820
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.
Upvotes: 26
Views: 14386
Reputation: 3882
There's a new solution available - ready to use in stable channel.
With the use of new DraggableScrollableController
you can now programatically show or hide the DraggableScrollableSheet
with or without an animation.
class TestWidget extends StatelessWidget {
final controller = DraggableScrollableController();
final minChildSize = 0.2;
@override
Widget build(BuildContext context) {
return DraggableScrollableSheet(
controller: controller,
minChildSize: minChildSize,
builder: _buildBody(),
);
}
void animatedHide() {
controller.animateTo(
minChildSize,
duration: const Duration(milliseconds: 100),
curve: Curves.easeOutBack,
);
}
}
Documentation available here: https://api.flutter.dev/flutter/widgets/DraggableScrollableController-class.html
Upvotes: 14
Reputation: 300
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(),
),
);
}
}
Upvotes: 21
Reputation: 261
You can reset the position of the DraggableScrollableSheet
to its initialChildSize
by 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 DraggableScrollableSheet
and 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.
Upvotes: 5