Builders Academy
Flutter — Développement Cross-Platform
1 of 3

Chapitre 1 · Leçon 1

Widgets Flutter

Tout est widget — construire une interface

Section 1

StatelessWidget vs StatefulWidget

Step 1

Créer un StatelessWidget

Un StatelessWidget est immuable — il affiche des données mais ne les modifie pas. Parfait pour les composants de présentation purs.

tutorial_card.dart

dart
1import 'package:flutter/material.dart';
2
3class TutorialCard extends StatelessWidget {
4  final String title;
5  final String level;
6  final int duration;
7  final Color color;
8  final VoidCallback? onTap;
9
10  const TutorialCard({
11    super.key,
12    required this.title,
13    required this.level,
14    required this.duration,
15    required this.color,
16    this.onTap,
17  });
18
19  
20  Widget build(BuildContext context) {
21    return GestureDetector(
22      onTap: onTap,
23      child: Card(
24        elevation: 2,
25        shape: RoundedRectangleBorder(
26          side: BorderSide(color: color, width: 3),
27          borderRadius: BorderRadius.circular(12),
28        ),
29        child: Padding(
30          padding: const EdgeInsets.all(16),
31          child: Column(
32            crossAxisAlignment: CrossAxisAlignment.start,
33            children: [
34              Text(
35                title,
36                style: Theme.of(context).textTheme.titleMedium?.copyWith(
37                  fontWeight: FontWeight.bold,
38                ),
39              ),
40              const SizedBox(height: 8),
41              Row(
42                children: [
43                  _LevelBadge(level: level, color: color),
44                  const SizedBox(width: 8),
45                  Text('$duration min',
46                    style: const TextStyle(color: Colors.grey)),
47                ],
48              ),
49            ],
50          ),
51        ),
52      ),
53    );
54  }
55}
56
57class _LevelBadge extends StatelessWidget {
58  final String level;
59  final Color color;
60
61  const _LevelBadge({required this.level, required this.color});
62
63  
64  Widget build(BuildContext context) {
65    return Container(
66      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
67      decoration: BoxDecoration(
68        color: color.withOpacity(0.15),
69        borderRadius: BorderRadius.circular(4),
70        border: Border.all(color: color.withOpacity(0.5)),
71      ),
72      child: Text(level,
73        style: TextStyle(color: color, fontSize: 12,
74          fontWeight: FontWeight.w600)),
75    );
76  }
77}

Step 2

StatefulWidget — état local

Un StatefulWidget maintient un état qui peut changer. setState() déclenche le rebuild du widget.

tutorial_card.dart

dart
1import 'package:flutter/material.dart';
2
3class TutorialCard extends StatelessWidget {
4  final String title;
5  final String level;
6  final int duration;
7  final Color color;
8  final VoidCallback? onTap;
9
10  const TutorialCard({
11    super.key,
12    required this.title,
13    required this.level,
14    required this.duration,
15    required this.color,
16    this.onTap,
17  });
18
19  
20  Widget build(BuildContext context) {
21    return GestureDetector(
22      onTap: onTap,
23      child: Card(
24        elevation: 2,
25        shape: RoundedRectangleBorder(
26          side: BorderSide(color: color, width: 3),
27          borderRadius: BorderRadius.circular(12),
28        ),
29        child: Padding(
30          padding: const EdgeInsets.all(16),
31          child: Column(
32            crossAxisAlignment: CrossAxisAlignment.start,
33            children: [
34              Text(
35                title,
36                style: Theme.of(context).textTheme.titleMedium?.copyWith(
37                  fontWeight: FontWeight.bold,
38                ),
39              ),
40              const SizedBox(height: 8),
41              Row(
42                children: [
43                  _LevelBadge(level: level, color: color),
44                  const SizedBox(width: 8),
45                  Text('$duration min',
46                    style: const TextStyle(color: Colors.grey)),
47                ],
48              ),
49            ],
50          ),
51        ),
52      ),
53    );
54  }
55}
56
57class _LevelBadge extends StatelessWidget {
58  final String level;
59  final Color color;
60
61  const _LevelBadge({required this.level, required this.color});
62
63  
64  Widget build(BuildContext context) {
65    return Container(
66      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
67      decoration: BoxDecoration(
68        color: color.withOpacity(0.15),
69        borderRadius: BorderRadius.circular(4),
70        border: Border.all(color: color.withOpacity(0.5)),
71      ),
72      child: Text(level,
73        style: TextStyle(color: color, fontSize: 12,
74          fontWeight: FontWeight.w600)),
75    );
76  }
77}

Section 2

Layouts — Column, Row, Stack

Step 3

Column, Row et Expanded

Column et Row sont les layouts fondamentaux. Expanded et Flexible contrôlent comment les enfants occupent l'espace disponible.

tutorial_card.dart

dart
1import 'package:flutter/material.dart';
2
3class TutorialCard extends StatelessWidget {
4  final String title;
5  final String level;
6  final int duration;
7  final Color color;
8  final VoidCallback? onTap;
9
10  const TutorialCard({
11    super.key,
12    required this.title,
13    required this.level,
14    required this.duration,
15    required this.color,
16    this.onTap,
17  });
18
19  
20  Widget build(BuildContext context) {
21    return GestureDetector(
22      onTap: onTap,
23      child: Card(
24        elevation: 2,
25        shape: RoundedRectangleBorder(
26          side: BorderSide(color: color, width: 3),
27          borderRadius: BorderRadius.circular(12),
28        ),
29        child: Padding(
30          padding: const EdgeInsets.all(16),
31          child: Column(
32            crossAxisAlignment: CrossAxisAlignment.start,
33            children: [
34              Text(
35                title,
36                style: Theme.of(context).textTheme.titleMedium?.copyWith(
37                  fontWeight: FontWeight.bold,
38                ),
39              ),
40              const SizedBox(height: 8),
41              Row(
42                children: [
43                  _LevelBadge(level: level, color: color),
44                  const SizedBox(width: 8),
45                  Text('$duration min',
46                    style: const TextStyle(color: Colors.grey)),
47                ],
48              ),
49            ],
50          ),
51        ),
52      ),
53    );
54  }
55}
56
57class _LevelBadge extends StatelessWidget {
58  final String level;
59  final Color color;
60
61  const _LevelBadge({required this.level, required this.color});
62
63  
64  Widget build(BuildContext context) {
65    return Container(
66      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
67      decoration: BoxDecoration(
68        color: color.withOpacity(0.15),
69        borderRadius: BorderRadius.circular(4),
70        border: Border.all(color: color.withOpacity(0.5)),
71      ),
72      child: Text(level,
73        style: TextStyle(color: color, fontSize: 12,
74          fontWeight: FontWeight.w600)),
75    );
76  }
77}

Topics and skills covered

  • Flutter
  • Widgets
  • Layout
  • Stateless
  • Stateful