-
|
Hey guys, Is it possible to achieve a behavior, where I have a handle in the top section of the sheet that can be used to scroll up and down at all times, also when the scrollable content inside the sheet is not at the top / bottom? I am struggling a bit to find a solution here and would appreciate your help! Thank you a lot. Best, |
Beta Was this translation helpful? Give feedback.
Answered by
fujidaiti
Apr 26, 2025
Replies: 2 comments 1 reply
-
|
@bschrdr exampleimport 'package:auto_route/auto_route.dart';
import 'package:drag_handle/main.gr.dart';
import 'package:flutter/material.dart';
import 'package:smooth_sheets/smooth_sheets.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(routerConfig: AppRouter().config());
}
}
@AutoRouterConfig()
class AppRouter extends RootStackRouter {
@override
List<AutoRoute> get routes => [
AutoRoute(
path: '/',
initial: true,
page: MainRoute.page,
children: [
AutoRoute(
initial: true,
page: ShellRoute.page,
children: [
CustomRoute(
initial: true,
page: FirstSheetRoute.page,
customRouteBuilder: <T>(context, child, page) {
return PagedSheetRoute(
scrollConfiguration: SheetScrollConfiguration(),
settings: page,
builder: (_) => Material(child: child),
);
},
),
CustomRoute(
page: SecondSheetRoute.page,
customRouteBuilder: <T>(context, child, page) {
return PagedSheetRoute(
scrollConfiguration: SheetScrollConfiguration(),
initialOffset: const SheetOffset(0.5),
snapGrid: SheetSnapGrid(
snaps: [
SheetOffset.absolute(
kBottomNavigationBarHeight +
MediaQuery.paddingOf(context).bottom,
),
const SheetOffset(0.5),
const SheetOffset(0.9),
],
),
settings: page,
builder: (_) => Material(child: child),
);
},
),
],
),
],
),
];
}
final sheetNavKey = GlobalKey<NavigatorState>();
@RoutePage()
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
return Stack(
children: [
Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
sheetNavKey.currentContext?.router.navigate(
FirstSheetRoute(),
);
},
child: Text('To FirstSheetPage'),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () {
sheetNavKey.currentContext?.router.navigate(
SecondSheetRoute(),
);
},
child: Text('To SecondSheetPage'),
),
],
),
),
),
SheetViewport(child: NavigationSheet()),
],
);
}
}
@RoutePage()
class ShellPage extends AutoRouter {
const ShellPage({super.key});
}
class NavigationSheet extends StatelessWidget {
const NavigationSheet({super.key});
@override
Widget build(BuildContext context) {
return PagedSheet(
decoration: SheetDecorationBuilder(
size: SheetSize.stretch,
builder: (context, child) {
const borderRadius = BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
);
return DecoratedBox(
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: borderRadius,
boxShadow: [
BoxShadow(
color: Colors.grey.withValues(alpha: 0.16),
offset: const Offset(0, -2),
blurRadius: 8,
),
],
),
child: ClipRRect(borderRadius: borderRadius, child: child),
);
},
),
navigator: AutoRouter(
navigatorKey: sheetNavKey,
builder: (_, child) {
return Stack(
children: [
child,
const Positioned(
top: 0,
left: 0,
right: 0,
child: IgnorePointer(child: DragHandle()),
),
],
);
},
),
);
}
}
@RoutePage()
class FirstSheetPage extends StatelessWidget {
const FirstSheetPage({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 300,
color: Colors.blue.shade200,
padding: EdgeInsets.only(top: 30),
child: Center(
child: ElevatedButton(
onPressed: () => context.router.navigate(SecondSheetRoute()),
child: Text('To SecondSheetPage'),
),
),
);
}
}
@RoutePage()
class SecondSheetPage extends StatelessWidget {
const SecondSheetPage({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: Colors.red.shade200,
padding: EdgeInsets.only(top: 30),
child: SingleChildScrollView(
child: Column(
children: List.generate(100, (index) {
return Text('$index');
}),
),
),
);
}
}
class DragHandle extends StatelessWidget {
const DragHandle({super.key});
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 30),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Center(
child: Container(
width: 120,
height: 6,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(10),
),
),
),
),
);
}
}
2025-04-24.22.51.25.mov |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
Any non-scrollable content in a sheet can serve as a drag handle: return Sheet(
...
scrollConfiguration: const SheetScrollConfiguration(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
// Drag handle
ColoredBox(
color: Colors.purple,
child: SizedBox.fromSize(
size: Size.fromHeight(64),
child: Center(
child: Icon(Icons.drag_handle),
),
),
),
Expanded(
child: ListView.builder(
...Full Codeimport 'package:flutter/material.dart';
import 'package:smooth_sheets/smooth_sheets.dart';
void main() {
runApp(const _BasicScrollableSheetExample());
}
class _BasicScrollableSheetExample extends StatelessWidget {
const _BasicScrollableSheetExample();
@override
Widget build(BuildContext context) {
return MaterialApp(
// Use a Stack to place the sheet on top of another widget.
home: Stack(
children: [
const Scaffold(),
Builder(builder: (context) {
return SheetViewport(
padding: EdgeInsets.only(
// Add top padding to avoid the status bar.
top: MediaQuery.viewPaddingOf(context).top,
),
child: const _MySheet(),
);
}),
],
),
);
}
}
class _MySheet extends StatelessWidget {
const _MySheet();
@override
Widget build(BuildContext context) {
return Sheet(
decoration: MaterialSheetDecoration(
size: SheetSize.stretch,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(20),
),
color: Theme.of(context).colorScheme.secondaryContainer,
elevation: 4,
),
initialOffset: SheetOffset(0.5),
snapGrid: const SheetSnapGrid(
snaps: [SheetOffset(0.5), SheetOffset(1)],
),
scrollConfiguration: const SheetScrollConfiguration(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
ColoredBox(
color: Colors.purple,
child: SizedBox.fromSize(
size: Size.fromHeight(64),
child: Center(
child: Icon(Icons.drag_handle),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 50,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
),
),
],
),
);
}
}draggablescrollable.mp4 |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by
bschrdr
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@bschrdr
Any non-scrollable content in a sheet can serve as a drag handle:
Full Code