edge_to_edge_plus 0.1.0
edge_to_edge_plus: ^0.1.0 copied to clipboard
Typed Android window insets, tappableElement-aware system bar protection and diagnostics for the mandatory edge-to-edge enforcement in Android 15 and 16.
import 'package:edge_to_edge_plus/edge_to_edge_plus.dart';
import 'package:flutter/material.dart';
import 'screens/before_after_screen.dart';
import 'screens/diagnostics_screen.dart';
import 'screens/inset_inspector_screen.dart';
import 'screens/scrolling_bottom_screen.dart';
import 'screens/solid_bottom_screen.dart';
Future<void> main() async {
// Optional, but it means the first frame already has real insets instead of
// zeros that correct themselves a frame later.
await EdgeToEdge.ensureInitialized();
runApp(const DemoApp());
}
/// The demo app.
///
/// One `EdgeToEdgeScope` above `MaterialApp` is the entire integration. There
/// are no edits to `MainActivity.kt`, no theme attributes, and nothing in
/// `AndroidManifest.xml`.
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) => const EdgeToEdgeScope(
child: MaterialApp(
title: 'edge_to_edge_plus',
debugShowCheckedModeBanner: false,
home: HomeScreen(),
),
);
}
/// A demo entry.
class Demo {
const Demo({
required this.title,
required this.subtitle,
required this.icon,
required this.screen,
});
final String title;
final String subtitle;
final IconData icon;
final Widget screen;
}
const List<Demo> demos = <Demo>[
Demo(
title: 'Inset inspector',
subtitle: 'Every inset type, live. Rotate, or open the keyboard.',
icon: Icons.straighten,
screen: InsetInspectorScreen(),
),
Demo(
title: 'Solid bottom',
subtitle: 'Sticky footer + SystemBarProtection.bottom',
icon: Icons.vertical_align_bottom,
screen: SolidBottomScreen(),
),
Demo(
title: 'Scrolling bottom',
subtitle: 'Full-bleed content under the navigation bar',
icon: Icons.view_day_outlined,
screen: ScrollingBottomScreen(),
),
Demo(
title: 'Before / after',
subtitle: 'One switch that turns the handling off',
icon: Icons.compare_arrows,
screen: BeforeAfterScreen(),
),
Demo(
title: 'Diagnostics',
subtitle: 'EdgeToEdge.diagnose() on this device',
icon: Icons.health_and_safety_outlined,
screen: DiagnosticsScreen(),
),
];
/// The demo index.
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
final insets = EdgeToEdgeScope.insetsOf(context);
final mode = EdgeToEdgeScope.navigationModeOf(context);
return EdgeToEdgeRegion.scrollingBottom(
backgroundBrightness: Theme.of(context).brightness,
child: Scaffold(
body: ListView(
// The list scrolls under both bars; SafeArea-style padding is applied
// to the content, not to the viewport, so the scroll is full-bleed.
padding: EdgeInsets.only(
top: insets.statusBars.top + 16,
bottom: insets.systemBars.bottom + 16,
),
children: <Widget>[
const Padding(
padding: EdgeInsets.fromLTRB(20, 8, 20, 4),
child: Text(
'edge_to_edge_plus',
style: TextStyle(fontSize: 28, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Text(
'${mode.name} navigation · '
'tappableElement ${insets.tappableElement.bottom.toStringAsFixed(0)}',
style: TextStyle(color: Theme.of(context).hintColor),
),
),
for (final demo in demos)
ListTile(
leading: Icon(demo.icon),
title: Text(demo.title),
subtitle: Text(demo.subtitle),
trailing: const Icon(Icons.chevron_right),
onTap: () => Navigator.of(context).push<void>(
MaterialPageRoute<void>(builder: (_) => demo.screen),
),
),
],
),
),
);
}
}