Files

234 lines
5.1 KiB
Markdown
Raw Permalink Normal View History

# 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:
```dart
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
```dart
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
```dart
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)
```dart
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
```dart
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
```dart
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.*