Site de trucs et astuces : https://freefluttersource.com/
Outils pratiques : https://medium.com/flutter-community/5-flutter-packages-tools-for-faster-more-productive-project-development-f8adbac05616
Pour des logs mises en valeur : logger.wtf(« WTF logs??« )
Conversion de JSON en classe : https://app.quicktype.io/
A) Ajout d’images (Assets) :
Click droit à la racine du projet : create Directory assets et create directory images
Puis Ajout dans le fichier pubsepc.yaml
assets:
- assets/images/lake.jpg
Pour inclure l’ensemble des images du dossier, juste préciser assets/images/
Utilisation de l’image dans le code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("Image from assets"), ), body: Image.asset('assets/images/lake.jpg'), // <-- image ), ); } }
B) Ajout d’image en provenance d’internet
// Get Image From Internet
String getUrlImage(Record record) {
String UrlImage = "https://picsum.photos/250?image=1042";
if (!record.artUri.isEmpty) {
if (isValidURL(record.artUri))
UrlImage = record.artUri;
}
return UrlImage;
}
///////////////////////////////////
// Function to validate URL
bool isValidURL(String url)
{
RegExp regExp = new RegExp("((http|https)://)(www.)?[a-zA-Z0-9@:%._\\+~#?&//=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%._\\+~#?&//=]*)");
if (url.isEmpty)
{
return false;
}
if(regExp.hasMatch(url))
{
return true;
}
else
{
return false;
}
}
C) Les échafaudages (Scaffold) :
Ressources : https://medium.com/flutterdevs/know-your-widgets-scaffold-in-flutter-292b8bc1281
Pour afficher plusieurs widget dans un Scaffold
Scaffold(
body: Column(
children: <Widget>[
//all the children widgets that you need
],
),
),
D) Les listes :
Sliver list : https://www.kindacode.com/article/flutter-sliverlist/ et https://pub.dev/packages/reorderables
Supprimer des items en glissant : https://flutter.dev/docs/cookbook/gestures/dismissible
Modifier l’ordre des items en glissant : https://flutterforyou.com/how-to-change-order-of-items-in-a-listview-in-flutter/
Modifier l’ordre et supprimer en glissant : https://stackoverflow.com/questions/62860457/how-to-use-reorderablelistview-with-dismissdirection-in-flutter
Liste avec multi sélection et recherche : https://github. com/CHB61/multi_select_flutter et https://pub.dev/packages/select_dialog
Séparation des éléments d’une liste avec join : https://www.woolha.com/tutorials/dart-join-list-to-string-with-separator-examples
Librairie pour actions en glissant : https://pub.dev/packages/flutter_slidable/example
Liste réorganisable et action en glissant (swip) : https://stackoverflow.com/questions/62860457/how-to-use-reorderablelistview-with-dismissdirection-in-flutter
Et demo de liste réorganisable : https://github.com/flutter-devs/flutter_reorderable_listview_demo
Gestion de plusieurs éléments par ligne via une classe :
https://www.kindacode.com/article/sorting-lists-in-dart/#Sorting_a_List_of_Objects
Tri des éléments d’une liste :
Avec liste composée de classe :
users.sort((a, b) => a.age.compareTo(b.age));
var intList = [0, 5, 2, 3, 8, 17, 11];
intList.sort();
print(intList);
var tringList = ['vue', 'kotlin','dart', 'angular', 'flutter'];
tringList.sort();
print(tringList);
- Tri de liste dynamiques :
List<dynamic> list = [
{
'name':'abc',
'other imformations':'-',
},
{
'name':'abc',
'other imformations':'-',
}
]
print(list..sort((a, b) => a['name'].compareTo(b['name'])));
- Avec la fonction compare, tri d’une liste d’objets :
class Customer {
String name;
int age;
Customer(this.name, this.age);
@override
String toString() {
return '{ ${this.name}, ${this.age} }';
}
}
main() {
List customers = [];
customers.add(Customer('Jack', 23));
customers.add(Customer('Adam', 27));
customers.add(Customer('Katherin', 25));
customers.sort((a, b) => a.age.compareTo(b.age));
print('Sort by Age: ' + customers.toString());
customers.sort((a, b) => a.name.compareTo(b.name));
print('Sort by Name: ' + customers.toString());
}
Sliver listes : pour le scrolling de grandes listes :https://www.kindacode.com/article/flutter-sliverlist/
Références :
https://stackoverflow.com/questions/59692815/how-do-i-call-a-network-image-type-in-a-listview
https://www.woolha.com/tutorials/dart-inserting-elements-into-list-examples
https://bezkoder.com/dart-list/#Sort_a_List_of_objects_in_DartFlutter
https://pusher.com/tutorials/flutter-listviews
Deux listes à l’écran : https://www.javaer101.com/en/article/11607355.html
D) Les boutons actions flottants (comme dans GMAIL)
Voir l’enregistrement automatique
Ils sont de deux types
- FloatingActionButton
- FloatingActionButton.extended
1. FloatingActionButton
Par défaut création d’un bouton circulaire avec un « child widget ». Et une méthode onPressed avec un « widget » non obligatoire.
2. FloatingActionButton.extended
Ressources : https://proandroiddev.com/a-deep-dive-into-floatingactionbutton-in-flutter-bf95bee11627
Et les toasts et fenêtres de dialogue et d’alerte :
fluttertoast: ^8.0.3
awesome_dialog: ^1.3.2
E) Menus/groupes de boutons :
Différence entre RaisedButton et ElevatedButton : https://www.codegrepper.com/code-examples/whatever/flutter+raisedbutton+vs+elevated+button et https://www.woolha.com/tutorials/flutter-using-elevatedbutton-widget-examples#:~:text=Elevated%20Button%20is%20one%20of,been%20available%20since%20Flutter%201.22. et https://www.kindacode.com/article/working-with-elevatedbutton-in-flutter/
https://pub.dev/packages/floating_action_row/example
@override
Widget build(BuildContext context) {
var children = List<Widget>();
children.add(
FloatingActionRowButton(
icon: Icon(Icons.close), //Icons.close)
color:Colors.red,
onTap: () {_Fin();},
),
);
children.add(
FloatingActionRowDivider(),
);
children.add(
FloatingActionRowButton(
icon: Icon(Icons.add),
onTap: () {},
),
);
children.add(
FloatingActionRowDivider(),
);
children.add(
FloatingActionRowButton(
icon: Icon(Icons.delete), //arrow_forward
onTap: () {},
),
);
puis....
floatingActionButton: FloatingActionRow(
children: children,
color: Colors.blueAccent,
elevation: 4,
),
https://pub.dev/packages/flutter_speed_dial
floatingActionButton: SpeedDial(
// both default to 16
marginRight: 18,
marginBottom: 20,
animatedIcon: AnimatedIcons.menu_close,
animatedIconTheme: IconThemeData(size: 22.0),
// this is ignored if animatedIcon is non null
// child: Icon(Icons.add),
visible: true,
// If true user is forced to close dial manually
// by tapping main button and overlay is not rendered.
closeManually: false,
curve: Curves.bounceIn,
overlayColor: Colors.black,
overlayOpacity: 0.5,
onOpen: () => print('OPENING DIAL'),
onClose: () => print('DIAL CLOSED'),
tooltip: 'Speed Dial',
heroTag: 'speed-dial-hero-tag',
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 8.0,
shape: CircleBorder(),
children: [
SpeedDialChild(
child: Icon(Icons.close),//Icons.accessibility),
backgroundColor: Colors.red,
label: 'Quit',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () => _Fin()//print('FIRST CHILD')
),
SpeedDialChild(
child: Icon(Icons.brush),
backgroundColor: Colors.blue,
label: 'Second',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () => print('SECOND CHILD'),
),
SpeedDialChild(
child: Icon(Icons.keyboard_voice),
backgroundColor: Colors.green,
label: 'Third',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () => print('THIRD CHILD'),
),
],
),
F) Bouton Image :
https://pub.dev/packages/imagebutton et https://medium.com/flutter-community/flutter-widgets-buttons-the-whole-picture-5662a3b58b8f
Et bouton avec ombre :
GestureDetector(
onTap: () => {},
child: Container(
height: 100,
width: 200,
child: Card(
child: Align(
child: ListTile(
title: Text(
"LYRICS",
style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
alignment: Alignment.center,
),
elevation: 16, // the size of the shadow
shadowColor: Colors.black, // shadow color
color: Colors.lightGreen,
)),
),
G) Effets d’animation sur bouton (INKWELL) :
Références :
https://api.flutter.dev/flutter/material/InkWell-class.html
https://www.geeksforgeeks.org/flutter-inkwell-widget/
https://www.kindacode.com/article/flutter-inkwell-examples/
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: 'InkWell',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String inkwell='';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('InkWell Widget'),
backgroundColor: Colors.green,
actions: <Widget>[
Text(
'GFG',
textScaleFactor: 3,
)
],
),
backgroundColor: Colors.lightBlue[50],
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Material(
color: Colors.amber,
child:
InkWell(
hoverColor: Colors.orange,
splashColor: Colors.red,
focusColor: Colors.yellow,
highlightColor: Colors.purple,
onTap: () {
setState(() {
inkwell='Inkwell Tapped';
});
},
onLongPress: () {
setState(() {
inkwell='InkWell Long Pressed';
});
},
child: Container(
//color: Colors.green,
width: 120,
height: 70,
child: Center(
child: Text(
'Inkwell',
textScaleFactor: 2,
style: TextStyle(fontWeight: FontWeight.bold),
))),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(inkwell,textScaleFactor: 2,),
)
],
),
),
);
}
}
H) Welcome Screen / Splash Screen / Ecran d’accueil :
Splash Screen au démarrage pour éviter un écran blanc : https://pub.dev/packages/flutter_native_splash
On Boarding screen : https://pub.dev/packages/introduction_screen
https://www.hellohpc.com/flutter-how-to-create-attractive-onboarding-intro-screen-easily/
I) Bottom Navigation Bar et Menu Drawer
À l’intérieur d’un scaffold, instanciez votre Navigation Bar et votre body. Vous pouvez également ajouter une appBar si besoin. Dans votre BottomNavigationBar, ajoutez un currentIndex pour définir l’item en cours, un onTap pour l’action au clic, et votre liste d’items avec une icone et un title.
Ce qui donne :
class PageAccueil extends StatefulWidget { PageAccueil({Key key, this.title}) : super(key: key); final String title; @override _MaPageAccueilEtat createState() => _MaPageAccueilEtat(); } class _MaPageAccueilEtat extends State { int _selectedDrawerIndex = 0; _getDrawerItemWidget(int pos) { switch (pos) { case 0: return new FirstFragment(); case 1: return new SecondFragment(); case 2: return new ThirdFragment(); default: return new Text(""); } } @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return new Scaffold( bottomNavigationBar: BottomNavigationBar( backgroundColor: Colors.blue, selectedItemColor: Colors.black, unselectedItemColor: Colors.white, type: BottomNavigationBarType.fixed, currentIndex: _selectedDrawerIndex, onTap: (int index) { setState(() { _selectedDrawerIndex = index; }); }, items: [ new BottomNavigationBarItem( icon: Icon(CupertinoIcons.dot_radiowaves_left_right), /*new ImageIcon(AssetImage('images/ic_logo_large.png')),*/ label: 'Radio'), new BottomNavigationBarItem( icon: Icon(CupertinoIcons.bookmark), label: 'Favoris'), new BottomNavigationBarItem( icon: Icon(CupertinoIcons.list_bullet), label: 'Chaines') ], ), body: _getDrawerItemWidget(_selectedDrawerIndex), ); }
Pour changer les couleurs de la navigation bar :
et following properties to change the background, selected and unselected colors
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.blue,
selectedItemColor: Colors.black,
unselectedItemColor: Colors.white,
type: BottomNavigationBarType.fixed,
...
)
Navigation dans les pages de la BottomBar par programme :
Navigator.of(context, rootNavigator: true).pushReplacement(
MaterialPageRoute(builder: (context) => new PageAccueil()));
Interception de l’action ‘Back’ bouton retour du téléphone :
Il est nécessaire d’utiliser, dans la page souhaitée, WillPopScope
class maClasse extends StatelessWidget { @override Widget build(BuildContext context) { return WillPopScope( onWillPop: () { print('Backbutton pressed (device or appbar button), do whatever you want.'); //trigger leaving and use own data //Navigator.pop(context, false); Navigator.of(context, rootNavigator: true).pushReplacement( MaterialPageRoute(builder: (context) => new PageAccueil())); //we need to return a future return Future.value(false); }, child: MaterialApp( debugShowCheckedModeBanner: false, title: 'Sélection des favoris', theme: ThemeData(....
et
J) Internationalisation :
Références : https://phrase.com/blog/posts/how-to-internationalize-a-flutter-app/
Références :
https://stackoverflow.com/questions/48582963/flutter-how-to-execute-when-clicking-back-button
https://stackoverflow.com/questions/50452710/catch-android-back-button-event-on-flutter
https://stackoverflow.com/questions/52322340/flutter-how-to-remove-bottom-navigation-with-navigation
https://homework.family/menu-bottomnavigationbar-dans-flutter/
https://medium.com/codechai/flutter-6-bottom-navigation-38b202d9ca23
Le même principe est à appliquer pour le navigation Drawer
K) SharedPreferences, gestion des préférences :
Ajouter la dépendance https://pub.dev/packages/shared_preferences/install
Cf. https://fluttercorner.com/how-to-store-and-get-data-from-shared-preferences-in-flutter/
Créer une classe
import 'package:shared_preferences/shared_preferences.dart';
class StorageUtil {
static StorageUtil _storageUtil;
static SharedPreferences _preferences;
static Future<StorageUtil> getInstance() async {
if (_storageUtil == null) {
var secureStorage = StorageUtil._();
await secureStorage._init();
_storageUtil = secureStorage;
}
return _storageUtil;
}
StorageUtil._();
Future _init() async {
_preferences = await SharedPreferences.getInstance();
}
/////////////////////////////////////////////////////////////
// String
// get string
static String getString(String key, {String defValue = ''}) {
if (_preferences == null) return defValue;
return _preferences.getString(key) ?? defValue;
}
// put string
static Future<bool> putString(String key, String value) {
if (_preferences == null) return null;
return _preferences.setString(key, value);
}
/////////////////////////////////////////////////////////////
// int
// get int
static int getInt(String key, {int defValue = 0}) {
if (_preferences == null) return defValue;
return _preferences.getInt(key) ?? defValue;
}
// put string
static Future<bool> putInt(String key, int value) {
if (_preferences == null) return null;
return _preferences.setInt(key, value);
}
//////////////////////////////////////////////
// clear all préférences
static Future<bool> clrString() {
SharedPreferences prefs = _preferences;
prefs.clear();
}
}
Utilisation :
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await StorageUtil.getInstance();
runApp(SharedPreference());
}
StorageUtil.putInt("key_min", actuminutes); SavedInt =StorageUtil.getInt("key_min");
L) JSON et MAP :
https://medium.com/flutter-community/parsing-complex-json-in-flutter-747c46655f51
M) Audio :
just_audio et audio_service
Exemples : https://github.com/raywalz/as1iso/blob/master/lib/main.dart
https://dev.to/paurakhsharma/floating-audio-player-in-flutter-13hj
https://github.com/flutter/flutter/issues/27489
N) Formatage des widgets, contraintes :
https://flutter.dev/docs/development/ui/layout/constraints
Pour afficher conditionnellement un widget :
condition ? Text("True") : Text("False"),
O) CircularProgressIndicator :
https://medium.com/flutterdevs/circularprogressindicator-linearprogressindicator-in-flutter-369013366a
@override Widget build(BuildContext context) { (...) return isLoading ? Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), SizedBox( height: 15, ), LinearProgressIndicator(), ], )) : Scaffold( ...
P) Détection d’Internet :
xhttps://flutteragency.com/check-whether-there-is-an-internet-connection-available/
Future<void> infoConnexion() async { try { final result = await InternetAddress.lookup('google.com'); if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { TextTitre = ''; InternetOk = true; } } on SocketException catch (_) { TextTitre = "Pas d'internet"; InternetOk = false; } setState(() {}); }
Puis dans initstate :
@override void initState() { super.initState(); infoConnexion(); ...}
Et dans le widget :
@override Widget build(BuildContext context) { return !InternetOk ? MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text(TextTitre), ), body: Center( child: Image.asset( 'assets/images/no_internet.png'), // <-- imageText( ), )) : new Scaffold(.................
Q) Internationalisation :
R) Publicité :
1°) S’inscrire à AdMob : https://apps.admob.com/v2/home
2°) Sous AdMob créer une application
https://pub.dev/packages/google_mobile_ads
3°) Créer une ou plusieurs annonces de type Bannière ou Interstitielle et récupérer l’ ID d’application et l’ID de bloc d’annonces
4°) Ajouter dans le fichier manifest.xml à la ligne android:value= la valeur « ID d’application »
<manifest>
<application>
<!-- Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713 -->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
</application>
</manifest>
5°) Modifiez le code de votre application pour insérer les annonces :
Intitialisez le Ads SDK en appelant MobileAds.instance.initialize()
une seule fois pour toute l’application
void main() {
WidgetsFlutterBinding.ensureInitialized();
MobileAds.instance.initialize();
runApp(MyApp());
}
Utilisez un code d’annonce de test fournit ici : https://developers.google.com/admob/android/test-ads#sample%5C_ad%5C_units
Créer une annonce :
final BannerAd myBanner = BannerAd( adUnitId: 'ca-app-pub-3940256099942544/6300978111', //-- Pour test size: AdSize.banner, request: AdRequest(), listener: AdListener(), );
Dans Widget Build charger l’annonce :
myBanner.load();
final AdWidget adWidget = AdWidget(ad: myBanner);
Puis afficher le widget de l’annonce dans l’arbre des widgets :
Container(
alignment: Alignment.center,
child: adWidget,
width: myBanner.size.width.toDouble(),
height: myBanner.size.height.toDouble(),
),
Attention, mettre à jour la version du sdk d’android (19 minimum) dans le fichier build.gradle
defaultConfig { applicationId "com.andrologiciels.xxx" minSdkVersion 19 targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName }
S) Case à cocher et Switch :
bool _checkbox = false; String _valbox="décoché"; CheckboxListTile( title: Text("Ne plus montrer cette introduction", style: TextStyle( fontWeight: FontWeight.bold, color: Colors.white)), value: _checkbox, onChanged: (newValue) { setState(() { _checkbox = newValue; StorageUtil.putInt("ShowIntro", 1); }); }, controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox )
Switch :
https://fluttergems.dev/switch/
https://pub.dev/packages/list_tile_switch/versions/0.0.2
Références :
https://developers.google.com/admob/flutter/quick-start
https://developers.google.com/admob/flutter/banner
T) Traduction et localisation :
- créer le répertoire qui contiendra les traductions (exemple langues) dans le répertoire assets (à créer) à la racine et ajouter dans le pubsepc.yaml
assets: - assets/langues/
2. Ajoutez la dépendance Easy Localization dans pubspec.yaml (exemple ici)
dependencies:
flutter:
sdk: flutter
# Internationalisation
easy_localization: 3.0.0
3. Dans votre code ajoutez pour la version null-safety 3.0.0 :
void main() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); runApp(EasyLocalization( child: MyApp(), supportedLocales: [ Locale('en', 'US'), Locale('ar', 'DZ'), Locale('de', 'DE'), Locale('ru', 'RU'), Locale('fr', 'FR') ], path: 'assets/langues', )); } Pour la version "normale" 2.3.3+1 : void main() { runApp( EasyLocalization( supportedLocales: [Locale('en', 'US'), Locale('fr', 'FR')], path: 'assets/langues', // <-- change patch to your fallbackLocale: Locale('en', 'US'), child: MyApp() ), ); } Et juste après Widget build(BuildContext context) { return MaterialApp( Ajouter localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, locale: context.locale,
Pour chaque textes à traduire, remplacer :
le texte par ‘texte_à_traduire’.tr(), exemple :
'title'.tr()
dans un widget Text : Text('msg').tr(args: ['Andrologiciels', 'Flutter']), avec dans le Json : "msg": "Bonjour {} dans le {} monde ",
avec un style de texte :
Text(('msg').tr(args: ['Andrologiciels', 'Flutter']),
style: TextStyle(
color: Colors.grey.shade900,
fontSize: 18,
fontWeight: FontWeight.bold)),
4. Créer les fichiers traduction en json
{
"title": "Hello",
4. Des assistances :
flutter pub run easy_localization:generate -f keys -o locale_keys.g.dart –source-dir ./assets/langues
Puis dans le code : LocaleKeys.title.tr(),
flutter pub run easy_localization:generate –source-dir ./assets/langues
La liste des codes des pays est ici et la liste des langues là
X) Utilitaires :
Test de code DART en ligne : https://dartpad.dartlang.org/flutter
Liste des icônes Cupertino Icons
Mais aussi pour les icônes : https://oblador.github.io/react-native-vector-icons/ avec le package https://pub.dev/packages/flutter_vector_icons/install
Expandable : A widget that expands a child of a Row, Column, or Flex so that the child fills the available space. Using an Expanded widget makes a child of a Row, Column, or Flex expand to fill the available space along the main axis (e.g., horizontally for a Row or vertically for a Column). https://www.google.com/search?q=flutter+use+of+expandzd&oq=flutter+use+of+expandzd&aqs=chrome..69i57.8982j0j4&client=ms-android-samsung-ss&sourceid=chrome-mobile&ie=UTF-8
Containers : https://stackoverflow.com/questions/58000474/how-to-add-more-than-one-container-in-body
Utilisation de variables globales : https://stackoverflow.com/questions/29182581/global-variables-in-dart
Multi-sélection et recherche dans une liste : https://pub.dev/packages/multi_select_flutter
Navigation dans l’application :
Il est nécessaire dans le widget de base de nommer la racine et de désigner les widgets fils
Exmple la racine »initialroute », sera nommée « / » et aura comme affectation le widget « toto »
puis on déclare les autres pages en les nommant (exemple « /second ») et en leur affectant un widget, ce qui donne :
initialRoute: '/', routes: { '/': (context) => MonWidgetPrincipal(), '/second': (context) => ReorderExample(), }
Code à placer à la place de :
home: MonWidgetPrincipal(),
Il faudra alors appeler les pages filles, à partir de la page « / » selon la syntaxe :
onTap: () { Navigator.pushNamed(context, '/second'); }, Exemple avec trois pages : import 'package:flutter/material.dart'; import 'package:flutter_basic_appli/pagedeux.dart'; import 'package:flutter_basic_appli/pagetrois.dart'; void main() { runApp( MaterialApp( title: 'Named Routes Demo', // Start the app with the "/" named route. In this case, the app starts // on the FirstScreen widget. initialRoute: '/', routes: { // When navigating to the "/" route, build the FirstScreen widget. '/': (context) => const FirstScreen(), // When navigating to the "/second" route, build the SecondScreen widget. '/second': (context) => const SecondScreen(), '/third': (context) => const ThirdScreen(), }, ), ); } class FirstScreen extends StatelessWidget { const FirstScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('First Screen'), ), body: Center( child: ElevatedButton( // Within the `FirstScreen` widget onPressed: () { // Navigate to the second screen using a named route. Navigator.pushNamed(context, '/second'); }, child: const Text('Launch screen'), ), ), ); } } Page 2 : import 'package:flutter/material.dart'; class SecondScreen extends StatelessWidget { const SecondScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Second Screen'), ), body: new Row( children: <Widget>[ ButtonTheme( minWidth: 25.0, height: 25.0, child: OutlinedButton.icon( label: Text("Page trois"), icon: Icon(Icons.save), style: OutlinedButton.styleFrom( primary: Colors.white, backgroundColor: Colors.blueGrey, onSurface: Colors.orangeAccent, elevation: 20, ), onPressed: () { Navigator.pushNamed(context, '/third'); })), ///////////////////////: ButtonTheme( minWidth: 25.0, height: 25.0, child: OutlinedButton.icon( label: Text("Début"), icon: Icon(Icons.cancel_outlined), style: OutlinedButton.styleFrom( primary: Colors.white, backgroundColor: Colors.blueGrey, onSurface: Colors.orangeAccent, elevation: 20, ), onPressed: () { Navigator.pop(context); }, )) ], ), ); } } Références : https://flutter.dev/docs/cookbook/navigation/navigation-basics
Pour simplement ouvrir une page :
Navigator.of(context).push(MaterialPageRoute(builder: (context) => MyNewPage()));
Fermeture de l’application :
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
Navigation entre deux pages :
Page première (aller à la deuxième page) :
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PageDeux()),
);
},
Page seconde (retour à la page précédente) :
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => MyApp()));
},
Références : https://mansik16.medium.com/navigate-between-screens-in-flutter-837ffdd22839 Orientation de l'écran en portrait :
@override void initState() { super.initState(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( statusBarColor: Colors.black, )); }
Retrait de la barre de statut :
SystemChrome.setEnabledSystemUIOverlays([])
;
Pour la rétablir : SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values)
.
Retrait de la barre de l’application (App Bar) :
// appBar: AppBar( // title: Text(appTitle), // ),
Toast et alertes :
Fluttertoast.showToast( msg: "Vous devez sélectionner au moins une radio favorite", toastLength: Toast.LENGTH_LONG, gravity: ToastGravity.CENTER, timeInSecForIosWeb: 1, backgroundColor: Colors.red, textColor: Colors.white, fontSize: 16.0 ); Références : https://pub.dev/packages/fluttertoast SnackBar : ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('selradiotttheme').tr())); Références : https://flutter.dev/docs/cookbook/design/snackbars
Alert Dialog :
Ci-dessous une boite d’alerte dialogue personnalisée avec couleurs et boutons arrondis
Future _ackAlert(BuildContext context) {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
title: Center(child: Text('Téléchargement de')),
content: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Text(
"blabla.mp3",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.red,
),
),
)
],
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ButtonTheme(
minWidth: 25.0,
height: 25.0,
child: OutlinedButton.icon(
label: Text("Ok"),
icon: Icon(Icons.save),
style: OutlinedButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors.blueGrey,
onSurface: Colors.orangeAccent,
elevation: 20,
),
onPressed: () {},
)),
///////////////////////:
ButtonTheme(
minWidth: 25.0,
height: 25.0,
child: OutlinedButton.icon(
label: Text("Cancel"),
icon: Icon(Icons.cancel_outlined),
style: OutlinedButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors.blueGrey,
onSurface: Colors.orangeAccent,
elevation: 20,
),
onPressed: () {},
))
],
),
]);
},
);
}
En cas d’annulation :
Navigator.of(context).pop(ConfirmAction.CANCEL);
Alert Dialog avec saisie de texte :
Future _asyncInputDialog(BuildContext context) async {
String teamName = '';
return showDialog(
context: context,
barrierDismissible: false,
// dialog is dismissible with a tap on the barrier
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
title: Text('Téléchargement'),
content: new Row(
children: [
new Expanded(
child: new TextField(
autofocus: true,
decoration: new InputDecoration(
labelText: 'Fichier', hintText: 'Blabla.mp3'),
onChanged: (value) {
teamName = value;
},
))
],
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ButtonTheme(
minWidth: 25.0,
height: 25.0,
child: OutlinedButton.icon(
label: Text("Ok"),
icon: Icon(Icons.save),
style: OutlinedButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors.blueGrey,
onSurface: Colors.orangeAccent,
elevation: 20,
),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.CANCEL);
Fluttertoast.showToast(
msg: "Téléchargement de ${teamName} en cours...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
},
)),
///////////////////////:
ButtonTheme(
minWidth: 25.0,
height: 25.0,
child: OutlinedButton.icon(
label: Text("Cancel"),
icon: Icon(Icons.cancel_outlined),
style: OutlinedButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors.blueGrey,
onSurface: Colors.orangeAccent,
elevation: 20,
),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.CANCEL);
},
))
],
),
///////////////////////////////////////////////////
],
);
},
);
}
Affichage de la boite d’alerte à l’ouverture d’une page :
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Trial',
home: Scaffold(
appBar: AppBar(title: Text('List scroll')), body: new MyHome()));
}
}
class MyHome extends StatelessWidget { // Wrapper Widget
@override
Widget build(BuildContext context) {
Future.delayed(Duration.zero, () => showAlert(context));
return Container(
child: Text("Hello world"),
);
}
void showAlert(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: Text("hi"),
));
}
}
Ou
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback(
(_) => _showStartDialog()
);
}
Future<void> _showStartDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('AlertDialog Title'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('This is a demo alert dialog.'),
Text('Would you like to approve of this message?'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('Approve'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Copier du texte dans le presse papier :
TextButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.focused))
return Colors.red;
return null; // Defer to the widget's default.
}),
),
onPressed: () {
final data = ClipboardData(text: _sCompo + '\n' + sMsg);
Clipboard.setData(data);
Fluttertoast.showToast(
msg: 'Lyrics copied in clipboard', //'no_reco'.i18n(),
textColor: Colors.red);
},
child: Text('Copy lyrics'),
)
Référence : https://tomicriedel.medium.com/how-to-copy-text-to-clipboard-in-flutter-flutter-small-explanations-dd085cefc079
Widget Visibilité :
Invisible example:
Visibility(
child: Text("Invisible"),
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: false,
),
Gone example:
Visibility(
child: Text("Gone"),
visible: false,
),
Références : https://stackoverflow.com/questions/44489804/how-to-show-hide-widgets-programmatically-in-flutter
Loading Animation widget :
https://pub.dev/packages/loading_animation_widget
Références : https://androidkt.com/flutter-alertdialog-example/