breakpoint 1.3.0
breakpoint: ^1.3.0 copied to clipboard
A Flutter plugin to calculate the material design breakpoints.
import 'package:breakpoint/breakpoint.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Breakpoint Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
),
),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.dark,
),
),
themeMode: ThemeMode.system,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final breakpoint = Breakpoint.fromConstraints(constraints);
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar.medium(
title: const Text('Breakpoint Gallery'),
actions: [
IconButton(
icon: const Icon(Icons.info_outline),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) => BreakpointInfoSheet(
breakpoint: breakpoint,
),
);
},
),
],
),
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: breakpoint.margin,
vertical: 16,
),
child: BreakpointInfoCard(breakpoint: breakpoint),
),
),
SliverPadding(
padding: EdgeInsets.symmetric(horizontal: breakpoint.margin),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: breakpoint.columns,
crossAxisSpacing: breakpoint.gutters,
mainAxisSpacing: breakpoint.gutters,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return GridItem(index: index);
},
childCount: 24,
),
),
),
SliverToBoxAdapter(
child: SizedBox(height: breakpoint.gutters),
),
],
),
);
});
}
}
class BreakpointInfoCard extends StatelessWidget {
const BreakpointInfoCard({
super.key,
required this.breakpoint,
});
final Breakpoint breakpoint;
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Card(
elevation: 0,
color: colorScheme.surfaceContainerHighest,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Current Layout',
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: colorScheme.primary,
),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: _InfoItem(
label: 'Device',
value: breakpoint.device.name,
icon: Icons.devices,
),
),
Expanded(
child: _InfoItem(
label: 'Window',
value: breakpoint.window.name,
icon: Icons.window,
),
),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: _InfoItem(
label: 'Columns',
value: '${breakpoint.columns}',
icon: Icons.view_column,
),
),
Expanded(
child: _InfoItem(
label: 'Gutters',
value: '${breakpoint.gutters}px',
icon: Icons.space_bar,
),
),
Expanded(
child: _InfoItem(
label: 'Margin',
value: '${breakpoint.margin}px',
icon: Icons.border_outer,
),
),
],
),
],
),
),
);
}
}
class _InfoItem extends StatelessWidget {
const _InfoItem({
required this.label,
required this.value,
required this.icon,
});
final String label;
final String value;
final IconData icon;
@override
Widget build(BuildContext context) {
return Row(
children: [
Icon(icon, size: 20, color: Theme.of(context).colorScheme.secondary),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: Theme.of(context).textTheme.bodySmall,
),
Text(
value,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
],
),
],
);
}
}
class GridItem extends StatelessWidget {
const GridItem({
super.key,
required this.index,
});
final int index;
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () {},
child: LayoutBuilder(builder: (context, constraints) {
final isSmall = constraints.maxHeight < 80;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
color: colorScheme.primaryContainer
.withValues(alpha: (index % 5 + 1) * 0.1),
child: Center(
child: Icon(
Icons.image,
size: isSmall ? 32 : 48,
color: colorScheme.primary.withValues(alpha: 0.5),
),
),
),
),
if (!isSmall)
Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Item $index',
style: Theme.of(context).textTheme.titleSmall,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Container(
height: 8,
width: 60,
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(4),
),
),
],
),
),
],
);
}),
),
);
}
}
class BreakpointInfoSheet extends StatelessWidget {
const BreakpointInfoSheet({
super.key,
required this.breakpoint,
});
final Breakpoint breakpoint;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(24),
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Breakpoint Details',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 16),
Text('Device Class: ${breakpoint.device}'),
Text('Window Size: ${breakpoint.window}'),
Text('Column Count: ${breakpoint.columns}'),
Text('Gutter Size: ${breakpoint.gutters}'),
Text('Margin Size: ${breakpoint.margin}'),
const SizedBox(height: 24),
],
),
);
}
}