Last active
March 1, 2025 16:47
-
-
Save emri99/74a4da7a18327814fd8a165949da449e to your computer and use it in GitHub Desktop.
Draggable flutter bottom sheet & Autoroute (flutter 3.16, auto_route 7.8.4)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'modal_bottom_sheet_autoroute.dart'; | |
export 'package:auto_route/auto_route.dart'; | |
export 'app_router.gr.dart'; | |
@AutoRouterConfig(replaceInRouteName: 'View,Route') | |
class AppRouter extends $AppRouter { | |
@override | |
final List<AutoRoute> routes = [ | |
AutoRoute(path: '/', page: HomeRoute.page), | |
ModalBottomSheetAutoRoute(path: 'sample', page: SampleRoute.page, barrierDismissible: false), | |
] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'app_router.dart'; | |
import 'modal_bottom_sheet_autoroute.dart'; | |
void main() => runApp(App()); | |
class App extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Center( | |
child: MaterialApp.router( | |
routerDelegate: AutoRouterDelegate(appRouter), | |
routeInformationParser: appRouter.defaultRouteParser(), | |
), | |
); | |
} | |
} | |
@RoutePage<void>() | |
class HomeView extends StatelessWidget { | |
const HomeView({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: const Text('Home'),), | |
body: Center( | |
child: ElevatedButton( | |
onPressed: () { | |
AutoRouter.of(context).push(const SampleRoute()); | |
}, | |
child: const Text('Open bottomsheet'), | |
), | |
), | |
); | |
} | |
} | |
@RoutePage<void>() | |
class SampleView extends StatelessWidget with DraggableScrollControllerMixin { | |
const SampleView({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return ListView.builder( | |
controller: getScrollController(context), | |
itemBuilder: (context, index) => ListTile(title: Text('Item $index')), | |
itemCount: 100, | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:auto_route/auto_route.dart'; | |
import 'package:flutter/material.dart'; | |
import 'modal_draggable_sheet.dart'; | |
class ModalBottomSheetAutoRoute extends CustomRoute { | |
ModalBottomSheetAutoRoute({ | |
required super.page, | |
super.path, | |
super.usesPathAsKey, | |
super.guards, | |
super.fullMatch, | |
super.meta, | |
super.maintainState, | |
super.fullscreenDialog, | |
super.children, | |
super.title, | |
super.restorationId, | |
super.keepHistory, | |
super.initial, | |
super.transitionsBuilder, | |
super.durationInMilliseconds, | |
super.reverseDurationInMilliseconds, | |
super.opaque, | |
super.barrierDismissible, | |
super.barrierLabel, | |
super.barrierColor, | |
double? fixedSize, | |
double initialSize = .5, | |
double minSize = .25, | |
double maxSize = .95, | |
ShapeBorder? shape, | |
bool? isScrollControlled, | |
bool? enableDrag, | |
bool? showDragHandle, | |
Color? backgroundColor, | |
bool? useSafeArea, | |
String? barrierOnTapHint, | |
}) : super( | |
customRouteBuilder: routeBuilderFactory( | |
initialChildSize: fixedSize ?? initialSize, | |
maxChildSize: fixedSize ?? maxSize, | |
minChildSize: fixedSize ?? minSize, | |
barrierColor: barrierColor, | |
barrierDismissible: barrierDismissible, | |
backgroundColor: backgroundColor, | |
barrierLabel: barrierLabel, | |
shape: shape, | |
isScrollControlled: isScrollControlled, | |
enableDrag: enableDrag, | |
showDragHandle: showDragHandle, | |
useSafeArea: useSafeArea, | |
barrierOnTapHint: barrierOnTapHint, | |
), | |
); | |
static CustomRouteBuilder routeBuilderFactory({ | |
required double initialChildSize, | |
required double minChildSize, | |
required double maxChildSize, | |
required bool barrierDismissible, | |
Color? backgroundColor, | |
Color? barrierColor, | |
ShapeBorder? shape, | |
bool? enableDrag, | |
bool? showDragHandle, | |
bool? isScrollControlled, | |
bool? useSafeArea, | |
String? barrierLabel, | |
String? barrierOnTapHint, | |
}) { | |
return <T>(BuildContext context, Widget child, AutoRoutePage<T> page) { | |
return ModalBottomSheetRoute<T>( | |
backgroundColor: backgroundColor, | |
isDismissible: barrierDismissible, | |
modalBarrierColor: barrierColor, | |
shape: shape, | |
isScrollControlled: isScrollControlled ?? true, | |
enableDrag: enableDrag ?? true, | |
showDragHandle: showDragHandle, | |
barrierLabel: barrierLabel, | |
settings: page, | |
useSafeArea: useSafeArea ?? false, | |
barrierOnTapHint: barrierOnTapHint, | |
builder: (context) { | |
return isScrollControlled ?? true | |
? ModalDraggableSheet( | |
initialChildSize: initialChildSize, | |
minChildSize: minChildSize, | |
maxChildSize: maxChildSize, | |
child: child, | |
) | |
: child; | |
}, | |
); | |
}; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
// this widgets can be used without autoroute | |
class ModalDraggableSheet extends StatelessWidget { | |
const ModalDraggableSheet({ | |
super.key, | |
required this.child, | |
this.initialChildSize = .5, | |
this.minChildSize = .25, | |
this.maxChildSize = .95, | |
}); | |
final Widget child; | |
final double initialChildSize; | |
final double minChildSize; | |
final double maxChildSize; | |
@override | |
Widget build(BuildContext context) { | |
return DraggableScrollableSheet( | |
initialChildSize: initialChildSize, | |
minChildSize: minChildSize, | |
maxChildSize: maxChildSize, | |
expand: false, | |
builder: (context, ScrollController scrollController) => DraggableScrollController( | |
scrollController: scrollController, | |
child: child, | |
), | |
); | |
} | |
} | |
/// this widget is responsible of supplying the scroll controller of a draggable | |
/// scrollable sheet to its children. | |
/// | |
/// * see | |
/// * [DraggableScrollControllerStateMixin] for stateful widget mixin | |
/// Use the getter [DraggableScrollControllerStateMixin.scrollController] | |
/// to get the scroll controller | |
/// * [DraggableScrollControllerStateMixin] for stateless widget mixin | |
/// Use the method [DraggableScrollControllerMixin.getScrollController] | |
/// to get the scroll controller | |
/// | |
class DraggableScrollController extends InheritedWidget { | |
const DraggableScrollController({ | |
super.key, | |
this.scrollController, | |
required super.child, | |
}); | |
final ScrollController? scrollController; | |
static ScrollController? of(BuildContext context, {bool listen = false}) { | |
if (listen) { | |
return context.dependOnInheritedWidgetOfExactType<DraggableScrollController>()?.scrollController; | |
} | |
final widget = context.getElementForInheritedWidgetOfExactType<DraggableScrollController>()?.widget | |
as DraggableScrollController?; | |
return widget?.scrollController; | |
} | |
@override | |
bool updateShouldNotify(covariant InheritedWidget oldWidget) { | |
return false; | |
} | |
} | |
/// mixin to simplify retrieving the scrollController on stateful widget that may be | |
/// inserted inside a [ModalDraggableSheet] | |
mixin DraggableScrollControllerStateMixin<T extends StatefulWidget> on State<T> { | |
ScrollController? get scrollController => DraggableScrollController.of(context); | |
} | |
/// mixin to simplify retrieving the scrollController on stateless widget that may be | |
/// inserted inside a [ModalDraggableSheet] | |
mixin DraggableScrollControllerMixin on StatelessWidget { | |
ScrollController? getScrollController(BuildContext context) => DraggableScrollController.of(context); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment