Add comprehensive Flutter cross-platform development guide covering: - Widget patterns and const optimization - Riverpod/Bloc state management - GoRouter navigation - Performance optimization - Testing strategies - Platform-specific implementations Made-with: Cursor
5.1 KiB
5.1 KiB
Widget Patterns
Flutter widget best practices covering const optimization, responsive layouts, hooks, and sliver patterns.
Optimized Widget Pattern
Always use const constructors for static widgets to prevent unnecessary rebuilds:
class OptimizedCard extends StatelessWidget {
final String title;
final VoidCallback onTap;
const OptimizedCard({
super.key,
required this.title,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(title, style: Theme.of(context).textTheme.titleMedium),
),
),
);
}
}
Extracting Const Widgets
class MyScreen extends StatelessWidget {
const MyScreen({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: const [
_Header(),
_Body(),
_Footer(),
],
);
}
}
class _Header extends StatelessWidget {
const _Header();
@override
Widget build(BuildContext context) {
return const Text('Header');
}
}
Responsive Layout
class ResponsiveLayout extends StatelessWidget {
final Widget mobile;
final Widget? tablet;
final Widget desktop;
const ResponsiveLayout({
super.key,
required this.mobile,
this.tablet,
required this.desktop,
});
static const double mobileBreakpoint = 650;
static const double desktopBreakpoint = 1100;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= desktopBreakpoint) return desktop;
if (constraints.maxWidth >= mobileBreakpoint) return tablet ?? mobile;
return mobile;
},
);
}
}
Breakpoint Reference
| Type | Width | Usage |
|---|---|---|
| Mobile | < 650pt | Single column, bottom nav |
| Tablet | 650-1100pt | Two columns, side nav optional |
| Desktop | > 1100pt | Multi-column, persistent nav |
Custom Hooks (flutter_hooks)
import 'package:flutter_hooks/flutter_hooks.dart';
class CounterWidget extends HookWidget {
const CounterWidget({super.key});
@override
Widget build(BuildContext context) {
final counter = useState(0);
final controller = useTextEditingController();
final isMounted = useIsMounted();
useEffect(() {
debugPrint('Widget mounted');
return () {
debugPrint('Widget disposed');
};
}, const []);
return Column(
children: [
Text('Count: ${counter.value}'),
ElevatedButton(
onPressed: () => counter.value++,
child: const Text('Increment'),
),
TextField(controller: controller),
],
);
}
}
Common Hooks
| Hook | Purpose |
|---|---|
useState |
Local state management |
useEffect |
Side effects with cleanup |
useMemoized |
Expensive computation caching |
useTextEditingController |
Text field controller |
useAnimationController |
Animation controller |
useFocusNode |
Focus management |
useIsMounted |
Check if widget is mounted |
Sliver Patterns
CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 200,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: const Text('Title'),
background: Image.network(imageUrl, fit: BoxFit.cover),
),
),
SliverPadding(
padding: const EdgeInsets.all(16),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(
key: ValueKey(items[index].id),
title: Text(items[index].title),
),
childCount: items.length,
),
),
),
const SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16),
child: Text('Footer'),
),
),
],
)
Sliver Types
| Sliver | Usage |
|---|---|
SliverAppBar |
Collapsing app bar |
SliverList |
Lazy list |
SliverGrid |
Lazy grid |
SliverToBoxAdapter |
Single non-sliver widget |
SliverPadding |
Add padding to sliver |
SliverFillRemaining |
Fill remaining space |
Key Usage Patterns
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Dismissible(
key: ValueKey(item.id),
child: ListTile(
key: ValueKey('tile_${item.id}'),
title: Text(item.title),
),
);
},
)
| Key Type | When to Use |
|---|---|
ValueKey |
Unique ID available |
ObjectKey |
Object identity matters |
UniqueKey |
Force rebuild |
GlobalKey |
Access state across tree |
Optimization Checklist
| Pattern | Implementation |
|---|---|
| const widgets | Add const to static widgets |
| Keys | Use ValueKey for list items |
| Select | ref.watch(provider.select(...)) |
| RepaintBoundary | Isolate expensive repaints |
| ListView.builder | Lazy loading for lists |
| const constructors | Always use when possible |
Flutter and Material Design are trademarks of Google LLC.