Astuces Flutter

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

https://stackoverflow.com/questions/54066268/how-to-show-a-widget-along-a-listview-on-the-same-screen-in-flutter/54066399

Deux listes à l’écran : https://www.javaer101.com/en/article/11607355.html

https://stackoverflow.com/questions/59947291/how-to-show-two-listview-on-the-same-screen-with-flutter

D) Les boutons actions flottants (comme dans GMAIL)

Voir l’enregistrement automatique

Ils sont de deux types

  1. FloatingActionButton
  2. 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 backgroundselected 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(....

Références : https://blog.logrocket.com/how-to-build-a-bottom-navigation-bar-in-flutter/#:~:text=BottomNavigationBar%20is%20a%20widget%20that,navigate%20to%20a%20given%20page

Code

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://nahid-ibne-akhtar.medium.com/flutter-assets-audio-player-a-guideline-to-build-an-audio-player-selecting-files-from-assets-bac388645f41

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"),

Références : https://stackoverflow.com/questions/49713189/how-to-use-conditional-statement-within-child-attribute-of-a-flutter-widget-cen

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 :

https://pub.dev/packages/intl

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://flutter.dev/ads

https://developers.google.com/admob/flutter/banner

T) Traduction et localisation :

  1. 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

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/

https://codesinsider.com/flutter-outlinedbutton-example/

https://github.com/RatelHub/rflutter_alert

Articles récents
Commentaires récents
fatima dans Bienvenue !
AdminDroid dans Bienvenue !
fatima dans Bienvenue !
Archives
Catégories