scroll_dismissible_page 0.1.0
scroll_dismissible_page: ^0.1.0 copied to clipboard
A Flutter page wrapper with scroll-aware swipe-down-to-dismiss. Nested scrollables keep working; dismiss only engages at the top edge.
import 'package:flutter/material.dart';
import 'package:scroll_dismissible_page/scroll_dismissible_page.dart';
void main() {
runApp(const ScrollDismissiblePageDemo());
}
class ScrollDismissiblePageDemo extends StatelessWidget {
const ScrollDismissiblePageDemo({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'scroll_dismissible_page',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF1B4DFF),
brightness: Brightness.light,
),
useMaterial3: true,
scaffoldBackgroundColor: const Color(0xFFF2F4F8),
),
home: const DemoHomePage(),
);
}
}
class DemoHomePage extends StatelessWidget {
const DemoHomePage({super.key});
void _openDetail(BuildContext context) {
Navigator.of(
context,
).push(MaterialPageRoute<void>(builder: (_) => const DemoDetailPage()));
}
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Scaffold(
appBar: AppBar(
title: const Text('Scroll Dismissible Page'),
centerTitle: false,
backgroundColor: scheme.surface,
surfaceTintColor: Colors.transparent,
),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
Text(
'Open a detail route, scroll normally, then swipe down from the '
'top to dismiss.',
style: Theme.of(
context,
).textTheme.bodyLarge?.copyWith(color: scheme.onSurfaceVariant),
),
const SizedBox(height: 24),
FilledButton.icon(
onPressed: () => _openDetail(context),
icon: const Icon(Icons.open_in_full),
label: const Text('Open gallery detail'),
),
],
),
);
}
}
class DemoDetailPage extends StatelessWidget {
const DemoDetailPage({super.key});
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return ScrollDismissiblePage(
backgroundColor: Colors.black.withValues(alpha: 0.45),
child: Scaffold(
backgroundColor: scheme.surface,
appBar: AppBar(
title: const Text('Look detail'),
backgroundColor: scheme.surface,
surfaceTintColor: Colors.transparent,
),
body: ListView.builder(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 32),
itemCount: 24,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
height: 220,
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
scheme.primaryContainer,
scheme.secondaryContainer,
],
),
),
alignment: Alignment.bottomLeft,
padding: const EdgeInsets.all(20),
child: Text(
'Swipe down to close',
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w700,
),
),
);
}
return Card(
margin: const EdgeInsets.only(bottom: 10),
elevation: 0,
color: scheme.surfaceContainerHighest.withValues(alpha: 0.55),
child: ListTile(
leading: CircleAvatar(
backgroundColor: scheme.primaryContainer,
child: Text('$index'),
),
title: Text('Detail row $index'),
subtitle: const Text('Scroll freely, then pull down at top'),
),
);
},
),
),
);
}
}