C'est un Framework développé par Google pour développer des applications pour Android, iOS, Windows, Mac, Linux, et le web.
En clair, codez une fois et compilez pour tout! (pour exporter vers des ios il est nécessaire d'avoir un Mac)
La doc de Flutter, en anglais, installer Flutter vous explique la démarche d'installation pour les 3 os (Windows, MacOS et Linux).
Si vous n'êtes pas à l'aise avec l'anglais il va falloir s'y faire...
En ce qui concerne l'éditeur, vous pouvez choisir IntelliJ, Android Studio ou Visual studio code. Pour la mise en place, suivez la doc réglage de l'éditeur.
Si vous avez choisi Vscode, placez vous dans votre dossier de travail et affichez le la palette de commande (ctrl+shift+p ou cmd+shift+p) et tapez flutter puis choisissez New Project
.
Il vous sera demandé le dossier de destination pour la création du projet.
Un fois la procédure terminée, vous pouvez tester le modèle proposé.
Si vous utilisez AndroidStudio(ou autre outil Jetbrain) ce sera new projet flutter
.
Après avoir généré un nouveau projet Flutter, remplacez le contenu de main.dart
par
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Salut Flutter',
home: Scaffold(
appBar: AppBar(
title: const Text('Salut les Flutterinos'),
),
body: const Center(
child: const Text('Il est vivant!!!'),
),
),
);
}
}
On utilise MaterialApp pour construire l'application ce qui nous permet d'utiliser la bibliothèque d'éléments pré-construits.
Dans pubspec.yaml
ajoutez les deux dépendances suivantes
list_french_words: ^0.1.0+1
recase: ^3.0.0
la première va nous donner une liste de 340000 mots français et l'autre va nous permettre de formater les String à notre idée. Le dépot de dart est ici
dans notre main.dart
ajoutons un mot français au hasard.
Créons d'abord une classe Mots qui va nous générer tout ça Mots.dart
dans un nouveau package model:
import 'dart:math';
import 'package:list_french_words/list_french_words.dart';
class Mots {
final nb = list_french_words.length;
random(){
var rd = new Random();
int rdFix = rd.nextInt(nb-1);
return list_french_words[rdFix];
}
}
Ajoutez cette méthode à la fin du main.dart
(en faisant les import qui vont bien) et modifiez le texte à afficher.
import 'package:app_one/model/Mots.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Salut Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Salut les Flutterinos'),
),
body: Center(
child: Text(
new Mots().random(),
style: TextStyle(fontSize: 24.0),
),
),
),
);
}
}
Pour faire un peu plus propre, nous allons utiliser les widget.
Nous allons utiliser les widget. Les widget sont statefull ou stateless. C'est à dire:
A la fin du main.dart
tapez simplement stful
et l'IDE génère le code pour vous. Il ne reste qu'à nommer le widget (RandomWords). Ensuite, nous déplaçons le code au bon endroit.
import 'package:app_one/model/Mots.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Salut Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Salut les Flutterinos'),
),
body: Center(
child: RandomWords(),
),
),
);
}
}
class RandomWords extends StatefulWidget {
@override
_RandomWordsState createState() => _RandomWordsState();
}
class _RandomWordsState extends State<RandomWords> {
@override
Widget build(BuildContext context) {
return Text(
new Mots().random(),
style: TextStyle(fontSize: 24.0),
);
}
}
Si vous lancez ce code les changements ne sont pas visibles mais ils seront utils juste après quand nous allons générer plusieurs mots dans une liste.
D'abord, on va créer une méthode qui nous permettra de générer nos mots.
Modifiez le fichier Mots.dart
.
import 'dart:math';
import 'package:list_french_words/list_french_words.dart';
import 'package:recase/recase.dart';
class Mots {
final nb = list_french_words.length;
/// génère un mot aléatoirement
random(){
var rd = new Random();
int rdFix = rd.nextInt(nb-1);
return list_french_words[rdFix];
}
/// génère une liste aléatoire de 10 mots
/// de type ReCase
generateMots() {
var list = <ReCase>[];
for (int i=0; i<11;i++){
list.add(new ReCase(random()));
}
return list;
}
}
Nous allons maintenant pouvoir modifier la classe _RandomWordsState
pour qu'elle génère des mots quand l'utilisateur fait défiler la liste.
On a d'abord besoin de 2 constantes:
class _RandomWordsState extends State<RandomWords> {
final List<Mot> _suggestions = <Mot>[];
...
Puis on ajoute une méthode qui va créer la ListView.
Widget _buildSuggestions() {
var mot = new Mots();
return ListView.builder(
padding: EdgeInsets.all(16.0),
itemBuilder: /*1*/ (context, i) {
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
if (index >= _suggestions.length) {
_suggestions.addAll(mot.generateMots()); /*4*/
}
return _buildRow(_suggestions[index]);
});
}
La méthode _buildSuggestions
fait appelle à la méthode _buildrow
qui construit les lignes
Widget _buildRow(ReCase suggestion) {
return ListTile(
title: Text(
suggestion.pascalCase,
style: TextStyle(fontSize: 24.0),
),
);
}
On modifie maintenant la méthode build
du _RandomWordsState
pour utiliser ce que nous venons d'écrire
@override
Widget build(BuildContext context) {
return _buildSuggestions();
}
Voilà !!! Vous devriez obtenir quelque chose comme ça
Nous allons ajouter des icônes à notre design et faire un peu de mise en place pour la suite.
D'abord ajoutez la constante pour sauvegarder les interactions
...
class _RandomWordsState extends State<RandomWords> {
final _suggestions = <ReCase>[];
final _saved = <ReCase>{};
On ajoute aussi alreadySaved
à la méthode _buildRow
pour s'assurer que la mot n'a pas été ajouté aux favoris.
Widget _buildRow(ReCase suggestion) {
final alreadySaved = _saved.contains(suggestion); //ici
...
Enfin, on ajoute les icones qui auront deux états.
Widget _buildRow(ReCase suggestion) {
final alreadySaved =_saved.contains(suggestion);
return ListTile(
title: Text(
suggestion.pascalCase,
style: TextStyle(fontSize: 24.0),
),
trailing: Icon( // ici..
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
);
}
Tada...
Pour le moment nous n'avons pas d'interactions.
Pour activer nos coeurs, nous allons ajouter activer onTap
pour que l'utilisateur puisse toucher le coeur et setState
pour sauvegarder l'état
Widget _buildRow(Mot suggestion) {
final alreadySaved = _saved.contains(suggestion);
return ListTile(
title: Text(
suggestion.formatPas(),
style: _biggerFont,
),
trailing: Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
onTap: () {//d'ici
setState(() {
if (alreadySaved) {
_saved.remove(suggestion);
} else {
_saved.add(suggestion);
}
});
},// jusque là
);
}
Je ne fais pas de screen mais maintenant les cœurs sont cliquables et s'affichent en rouge.
Pour faire ça on va d'abord ajouter une action sur notre appBar
dans la méthode build de _RandomWordsState
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Mot aléatoires'),
actions: [ //ici
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
La fonction _pushSaved
est donc à créer:
void _pushSaved() {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
final tiles = _saved.map(
(ReCase pair) {
return ListTile(
title: Text(
pair.pascalCase,
style: TextStyle(fontSize: 24.0),
),
);
},
);
final divided = ListTile.divideTiles(
context: context,
tiles: tiles,
).toList();
return Scaffold(
appBar: AppBar(
title: Text('Suggestions sauvées'),
),
body: ListView(children: divided),
);
},
),
);
}
Cette méthode va créer une nouvelle page à partir des mots que nous aurons sélectionnés.
Nous avons deux barres et une couleur inadaptée. Pour les barres, on va modifier la méthode build
de MyApp
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mes Mots',
home: RandomWords()
);
}
}
Enfin un peu d'esthetique:
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mes Mots',
debugShowCheckedModeBanner: false, // cacher le ruban debug
theme: ThemeData(
primaryColor: Colors.white // le blanc c'est plus chic
),
home: RandomWords()
);
}
Et voilà