iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Widgets

Everything in Flutter is a widget. Composition over inheritance: small widgets compose into bigger ones. StatelessWidget renders props; StatefulWidget holds local state.

Stateless, Stateful, composition

EXAMPLE
import 'package:flutter/material.dart';

// 1) Stateless — pure function of props
class Badge extends StatelessWidget {
    final String label;
    final Color color;
    const Badge({super.key, required this.label, this.color = Colors.grey});

    @@override
    Widget build(BuildContext context) {
        return Container(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            decoration: BoxDecoration(
                color: color.withOpacity(0.1),
                border: Border.all(color: color),
                borderRadius: BorderRadius.circular(12),
            ),
            child: Text(label, style: TextStyle(color: color, fontSize: 12)),
        );
    }
}

// 2) Stateful — holds mutable local state
class Counter extends StatefulWidget {
    const Counter({super.key});
    @@override State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
    int _n = 0;

    @@override
    Widget build(BuildContext context) {
        return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
                Text('Count: $_n', style: Theme.of(context).textTheme.titleLarge),
                Row(children: [
                    OutlinedButton(onPressed: () => setState(() => _n--), child: const Text('-')),
                    const SizedBox(width: 8),
                    FilledButton(onPressed: () => setState(() => _n++), child: const Text('+')),
                ]),
            ],
        );
    }
}

// 3) Composition — build big widgets from small ones
class ProductCard extends StatelessWidget {
    final String name;
    final double price;
    final String image;
    final VoidCallback? onTap;
    const ProductCard({super.key, required this.name, required this.price, required this.image, this.onTap});

    @@override
    Widget build(BuildContext context) {
        final cs = Theme.of(context).colorScheme;
        return InkWell(
            onTap: onTap,
            borderRadius: BorderRadius.circular(12),
            child: Card(
                elevation: 0,
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                clipBehavior: Clip.antiAlias,
                child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                        AspectRatio(aspectRatio: 4/3, child: Image.network(image, fit: BoxFit.cover)),
                        Padding(
                            padding: const EdgeInsets.all(12),
                            child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                    Text(name, style: Theme.of(context).textTheme.titleMedium, maxLines: 1, overflow: TextOverflow.ellipsis),
                                    const SizedBox(height: 4),
                                    Text('$${price.toStringAsFixed(2)}', style: TextStyle(color: cs.primary)),
                                ],
                            ),
                        ),
                    ],
                ),
            ),
        );
    }
}

// 4) Lifecycle methods (State<T>)
//   initState     : once, before first build — set up subscriptions, controllers
//   didChangeDependencies : whenever inherited widgets change
//   build         : on every rebuild
//   didUpdateWidget: on parent rebuild with new props
//   deactivate    : removed from tree
//   dispose       : final cleanup — controllers, streams

class Timer1 extends StatefulWidget {
    @@override State<Timer1> createState() => _Timer1State();
}
class _Timer1State extends State<Timer1> {
    late final Timer _t;
    int _s = 0;
    @@override void initState() {
        super.initState();
        _t = Timer.periodic(const Duration(seconds: 1), (_) => setState(() => _s++));
    }
    @@override void dispose() { _t.cancel(); super.dispose(); }
    @@override Widget build(BuildContext context) => Text('Elapsed: $_s');
}

// 5) const widgets — perf win
// Mark constructors const where possible. Const widgets are compile-time constants,
// reused across rebuilds without allocating new objects.

// 6) Common pitfalls
//   • Don't put expensive work in build() — it runs on every frame
//   • Don't access InheritedWidget (Theme, MediaQuery) in initState — use didChangeDependencies
//   • Always dispose controllers, animations, streams
//   • Use Key for items in lists that may reorder

Why it matters

Composition + small const widgets is the Flutter performance secret. const ProductCard(...) is free across rebuilds; non-const allocates every frame. Mark constructors const aggressively.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Everything is a Widget — even padding, alignment, themes.
Text('hi')
Icon(Icons.star)
Padding(padding: EdgeInsets.all(8), child: Text('x'))
Try it Yourself »

Test yourself

Q1. In Flutter, almost everything is…
Q2. Widgets are typically…
Q3. Combine vertical widgets with…

Discussion

Loading…