Fermer

avril 22, 2020

Développement Web et de bureau réactif avec Flutter


À propos de l'auteur

Passionné de Flutter et Linux, auteur du livre Programming Flutter avec la bibliothèque pragmatique. Blogs plus, tweets moins.
En savoir plus sur
Carmine

Flutter a déjà fait sensation sur la scène du développement mobile. Maintenant, il prend également de plus gros appareils. Voici ce que vous devez savoir pour être prêt à assumer la tâche de développer des applications Web et de bureau à l'aide de cette merveilleuse infrastructure multiplateforme.

Ce didacticiel n'est pas une introduction à Flutter lui-même. Il existe de nombreux articles, vidéos et plusieurs livres disponibles en ligne avec des introductions simples qui vous aideront à apprendre les bases de Flutter. Au lieu de cela, nous couvrirons les deux objectifs suivants:

  1. L'état actuel du développement non mobile Flutter et comment vous pouvez exécuter le code Flutter dans le navigateur, sur un ordinateur de bureau ou portable;
  2. Comment créer des applications réactives en utilisant Flutter, afin que vous puissiez voir sa puissance – en particulier en tant que framework Web – en plein écran, se terminant par une note sur le routage basé sur l'URL.

Allons-y!

Qu'est-ce que Flutter, pourquoi c'est important, Ce qu'il a évolué, où il va

Flutter est le dernier cadre de développement d'applications de Google. Google l'envisage comme universel: il permettra d'exécuter le même code sur les smartphones de toutes les marques, sur les tablettes et sur les ordinateurs de bureau et portables en tant qu'applications natives ou en tant que pages Web.

C'est un projet très ambitieux, mais Google a connu un succès incroyable jusqu'à présent, en particulier sous deux aspects: en créant un cadre vraiment indépendant de la plate-forme pour les applications natives Android et iOS qui fonctionne très bien et est entièrement prêt pour une utilisation en production, et en créant un cadre Web frontal impressionnant qui peut partager 100% du code avec une application Flutter compatible.

Dans la section suivante, nous allons voir ce qui rend l'application compatible et quel est l'état du développement Flutter non mobile à l'heure actuelle.

Non- Développement mobile avec Flutter

Le développement non mobile avec Flutter a été publié pour la première fois de manière significative lors de Google I / O 2019. Cette section explique comment le faire fonctionner et quand il fonctionne.

Comment activer le Web et Développement de bureau [19659015] Pour activer le développement Web, vous devez d'abord être sur le canal bêta de Flutter. Il y a deux façons d'arriver à ce point:

  • Installez Flutter directement sur le canal bêta en téléchargeant la dernière version bêta appropriée à partir de l'archive du SDK .
  • Si Flutter est déjà installé, passez à le canal bêta avec $ flutter channel beta puis effectuez le changement lui-même en mettant à jour votre version Flutter (qui est en fait un git pull sur le dossier d'installation Flutter) avec $ flutter upgrade .

Après cela, vous pouvez exécuter ceci:

 $ flutter config --enable-web 

La prise en charge du bureau est beaucoup plus expérimentale, notamment en raison d'un manque d'outils pour Linux et Windows, ce qui rend le développement de plugins particulièrement pénible, et du fait que les API utilisées sont destinées à une utilisation en preuve de concept et non à la production. Contrairement au développement Web, qui utilise le compilateur dart2js éprouvé pour les versions, qui ne sont même pas prises en charge pour les applications de bureau natives Windows et Linux.

Remarque : Prise en charge de macOS est légèrement meilleur que la prise en charge de Windows et Linux, mais il n'est toujours pas aussi bon que la prise en charge du Web et pas aussi bon que la prise en charge complète des plates-formes mobiles.

Pour activer la prise en charge du développement de bureau, vous devez passer au canal de publication maître en suivant les mêmes étapes décrites précédemment pour le canal bêta . Exécutez ensuite ce qui suit en remplaçant par linux windows ou macos :

 $ flutter config --enable-  -desktop 

À ce stade, si vous rencontrez des problèmes avec l'une des étapes suivantes que je vais décrire parce que l'outil Flutter ne fait pas ce que je dis qu'il devrait faire, voici quelques étapes de dépannage courantes: [19659016] Exécutez flutter doctor pour vérifier les problèmes. Un effet secondaire de cette commande Flutter est qu'elle doit télécharger tous les outils dont elle n'a pas besoin.

  • Exécutez mise à niveau de flutter .
  • Éteignez-la puis rallumez-la. L'ancienne réponse de l'assistance technique de niveau 1 du redémarrage de votre ordinateur pourrait être exactement ce dont vous avez besoin pour pouvoir profiter de toutes les richesses de Flutter.
  • Exécution et création d'applications Web Flutter

    Le support Web Flutter n'est pas mauvais du tout, et cela se reflète dans la facilité de développement pour le Web.

    L'exécution de ce…

     $ flutter devices 

    … devrait afficher immédiatement une entrée pour quelque chose comme ceci:

     Web Server • serveur Web • web-javascript • Outils Flutter 

    De plus, l'exécution du navigateur Chrome devrait également faire apparaître une entrée pour Flutter. L'exécution de flutter s'exécute sur un compatible projet Flutter (plus d'informations plus tard) lorsque le seul «périphérique connecté» apparaissant est le serveur Web, Flutter démarrera un serveur Web sur . ] localhost: qui vous permettra d'accéder à votre application Web Flutter à partir de n'importe quel navigateur.

    Si vous avez installé Chrome mais qu'il ne s'affiche pas, vous devez définir la variable d'environnement CHROME_EXECUTABLE sur le chemin d'accès au fichier exécutable Chrome.

    Exécution et création d'applications Flutter Desktop

    Après avoir activé la prise en charge Flutter Desktop, vous pouvez exécuter une application Flutter en mode natif sur votre poste de travail de développement avec flutter run -d [19659040]en remplaçant par la même valeur que vous avez utilisée lors de l'activation de la prise en charge du bureau. Vous pouvez également créer des fichiers binaires dans le répertoire build avec flutter build .

    Avant de pouvoir faire tout cela, cependant, vous devez avoir un répertoire contenant ce que Flutter doit construire pour votre plateforme. Il sera créé automatiquement lorsque vous créerez un nouveau projet, mais vous devrez le créer pour un projet existant avec flutter create. . De plus, les API Linux et Windows sont instables, vous devrez donc peut-être les régénérer pour ces plates-formes si l'application cesse de fonctionner après une mise à jour Flutter.

    Quand une application est-elle compatible?

    Qu'est-ce que j'ai toujours voulu dire en mentionnant qu'une application Flutter doit être un «projet compatible» pour qu'elle fonctionne sur le bureau ou sur le Web? En termes simples, je veux dire qu'il ne doit pas utiliser de plugin qui n'a pas d'implémentation spécifique à la plate-forme sur laquelle vous essayez de construire.

    Pour que ce point soit absolument clair pour tout le monde et pour éviter tout malentendu, veuillez noter qu'un plugin Flutter est un package Flutter particulier qui contient le code spécifique à la plate-forme qui lui est nécessaire pour fournir ses fonctionnalités.

    Par exemple, vous pouvez utiliser le Package url_launcher développé par Google autant que vous le souhaitez (et vous voudrez peut-être, étant donné que le Web est construit sur des hyperliens).

    Un exemple de package développé par Google, le dont l'utilisation empêcherait le développement Web est path_provider qui est utilisé pour obtenir le chemin de stockage local dans lequel enregistrer les fichiers. Ceci est un exemple de package qui, incidemment, n'est d'aucune utilité pour une application Web, donc ne pas pouvoir l'utiliser n'est pas vraiment une erreur, sauf pour le fait que vous devez changer votre code pour pour fonctionner sur le Web si vous l'utilisez.

    Par exemple, vous pouvez utiliser le package shared_preferences qui repose sur HTML localStorage sur le Web.

    Des mises en garde similaires sont valables en ce qui concerne les plates-formes de bureau: très peu de plug-ins sont compatibles avec les plates-formes de bureau et, comme il s'agit d'un thème récurrent, beaucoup plus de travail doit être fait du côté du bureau que ce qui est vraiment nécessaire sur Flutter pour le Web. 19659053] Création de mises en page réactives dans Flutter

    En raison de ce que j'ai décrit ci-dessus et pour des raisons de simplicité, je vais supposer pour le reste de cet article que votre plate-forme cible est le Web, mais les concepts de base s'appliquent au développement de bureau

    Le soutien du Web comporte des avantages et des responsabilités. Être à peu près obligé de prendre en charge différentes tailles d'écran peut sembler un inconvénient, mais considérez que l'exécution de l'application dans les navigateurs Web vous permet de voir très facilement à quoi ressemblera votre application sur des écrans de différentes tailles et proportions, sans avoir à exécuter séparément émulateurs d'appareils mobiles.

    Parlons maintenant du code. Comment pouvez-vous rendre votre application réactive?

    Il y a deux perspectives à partir desquelles cette analyse est effectuée:

    1. "Quels widgets suis-je en train d'utiliser ou puis-je utiliser qui peuvent ou doivent s'adapter à des écrans de tailles différentes?"
    2. "Comment puis-je obtenir des informations sur la taille de l'écran et comment l'utiliser pour écrire du code d'interface utilisateur?"

    Nous répondrons à la première question plus tard. Parlons d'abord de ce dernier, car il peut être traité très facilement et est au cœur du problème. Il existe deux façons de procéder:

    1. Une façon consiste à extraire les informations de la MediaQueryData de la racine MediaQuery InheritedWidget qui doit exister dans l'arborescence des widgets pour qu'une application Flutter fonctionne (elle fait partie de MaterialApp / WidgetsApp / CupertinoApp ), que vous pouvez obtenir, comme n'importe quelle autre InheritedWidget avec MediaQuery .of (contexte) qui a une propriété size qui est de type Size et qui a donc deux width et height propriétés du type double .
    2. L'autre méthode consiste à utiliser un LayoutBuilder qui est un widget de générateur (tout comme un StreamBuilder ou a FutureBuilder ) qui passe à la fonction de constructeur (avec le contexte ) a BoxCons traints objet qui a minHeight maxHeight minWidth et maxWidth propriétés.

    Voici un exemple de DartPad en utilisant la MediaQuery pour obtenir des contraintes, dont le code est le suivant:

     import 'package: flutter / material.dart';
    
    void main () => runApp (MyApp ());
    
    classe MyApp étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        MaterialApp (
          accueil: MyHomePage ()
        );
    }
    
    classe MyHomePage étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        Échafaud(
          corps: Centre (
            enfant: Colonne (
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              enfants: [
                Text(
                  "Width: ${MediaQuery.of(context).size.width}",
                  style: Theme.of(context).textTheme.headline4
                ),
                Text(
                  "Height: ${MediaQuery.of(context).size.height}",
                  style: Theme.of(context).textTheme.headline4
                )
              ]
           )
         )
       );
    } 

    Et voici celui qui utilise le LayoutBuilder pour la même chose:

     import 'package: flutter / material.dart';
    
    void main () => runApp (MyApp ());
    
    classe MyApp étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        MaterialApp (
          accueil: MyHomePage ()
        );
    }
    
    classe MyHomePage étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        Échafaud(
          corps: LayoutBuilder (
            constructeur: (contexte, contraintes) => Centre (
              enfant: Colonne (
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                enfants: [
                  Text(
                    "Width: ${constraints.maxWidth}",
                    style: Theme.of(context).textTheme.headline4
                  ),
                  Text(
                    "Height: ${constraints.maxHeight}",
                    style: Theme.of(context).textTheme.headline4
                  )
                ]
             )
           )
         )
      );
    } 

    Maintenant, réfléchissons aux widgets qui peuvent s'adapter aux contraintes.

    Tout d'abord, réfléchissons aux différentes façons de disposer plusieurs widgets en fonction de la taille de l'écran.

    Le widget le plus utilisé s'adapte facilement est le GridView . En fait, un GridView construit à l'aide du constructeur GridView.extent n'a même pas besoin de votre implication pour être réactif, comme vous pouvez le voir dans cet exemple très simple :

     import 'package: flutter / material.dart';
    
    void main () => runApp (MyApp ());
    
    classe MyApp étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        MaterialApp (
          accueil: MyHomePage ()
        );
    }
    
    classe MyHomePage étend StatelessWidget {
      Liste finale  éléments = [
        "Zero",
        "One",
        "Two",
        "Three",
        "Four",
        "Five",
        "Six",
        "Seven",
        "Eight",
        "A Million Billion Trillion",
        "A much, much longer text that will still fit"
      ];
    
    
      @passer outre
      Construction du widget (contexte) =>
        Échafaud(
          corps: GridView.extent (
            maxCrossAxisExtent: 130.0,
            crossAxisSpacing: 20,0,
            mainAxisSpacing: 20.0,
            children: elements.map ((el) => Card (child: Center (child: Padding (padding: EdgeInsets.all (8.0), child: Text (el)))))) toList ()
          )
       );
    } 

    Vous pouvez adapter le contenu de différentes tailles en modifiant le maxCrossAxisExtent .

    Cet exemple a principalement servi à montrer l'existence du GridView.extent GridView constructeur, mais une manière beaucoup plus intelligente de le faire serait d'utiliser un GridView.builder avec un SliverGridDelegateWithMaxCrossAxisExtent dans ce cas où les widgets à afficher dans la grille sont créés dynamiquement à partir de une autre structure de données, comme vous pouvez le voir dans cet exemple :

     import 'package: flutter / material.dart';
    
    void main () => runApp (MyApp ());
    
    classe MyApp étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        MaterialApp (
          accueil: MyHomePage ()
        );
    }
    
    classe MyHomePage étend StatelessWidget {
      Liste finale  éléments = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];
    
    
      @passer outre
      Construction du widget (contexte) =>
        Échafaud(
          corps: GridView.builder (
            itemCount: elements.length,
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent (
              maxCrossAxisExtent: 130.0,
              crossAxisSpacing: 20,0,
              mainAxisSpacing: 20.0,
            ),
            itemBuilder: (context, i) => Carte (
              enfant: Centre (
                enfant: rembourrage (
                  remplissage: EdgeInsets.all (8.0), enfant: texte (éléments [i])
                )
              )
            )
          )
       );
    } 

    Un exemple d'adaptation de GridView à différents écrans est ma page de destination personnelle qui est une application Web Flutter très simple composée d'une GridView avec un tas de cartes tout comme cet exemple de code précédent, sauf que les Cartes sont un peu plus complexes et plus grandes.

    Un changement très simple qui pourrait être apporté aux applications conçues pour les téléphones serait de remplacer un Tiroir avec un menu permanent à gauche lorsqu'il y a de l'espace.

    Par exemple, nous pourrions avoir un ListView de widgets, comme le suivant, qui est utilisé pour la navigation: [19659066] Le menu de classe étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) => ListView (
        enfants: [
    FlatButton(
    onPressed: () {},
    child: ListTile(
    leading: Icon(Icons.looks_one),
    title: Text("First Link"),
    )
    ),
    FlatButton(
    onPressed: () {},
    child: ListTile(
    leading: Icon(Icons.looks_two),
    title: Text("Second Link"),
    )
    )
    ]
      );
    }

    Sur un smartphone, un endroit commun à utiliser qui serait à l'intérieur d'un tiroir (également connu sous le nom de menu hamburger).

    Des alternatives à cela seraient le BottomNavigationBar ou le TabBar en combinaison avec le TabBarView mais avec les deux, nous devrons apporter plus de modifications que ce qui est requis avec le tiroir, nous allons donc nous en tenir au tiroir. [19659010] Pour n'afficher que le tiroir contenant le menu que nous avons vu précédemment sur des écrans plus petits, vous écririez du code qui ressemble à l'extrait suivant, en vérifiant la largeur à l'aide du MediaQuery.of (context) et en passant un objet Drawer à l'échafaudage uniquement si sa valeur de largeur est inférieure à une largeur que nous pensons appropriée pour notre application:

     Échafaud(
        appBar: AppBar (/ * ...  * /),
        tiroir: MediaQuery.of (context) .size.width <500?
        Tiroir(
          enfant: Menu (),
        ):
        nul,
        corps: / * ...  * /
    ) 

    Maintenant, réfléchissons au corps de l'échafaudage . Comme exemple de contenu principal de notre application, nous utiliserons le GridView que nous avons construit précédemment, que nous conservons dans un widget séparé nommé Content pour éviter toute confusion:

     class Content étend StatelessWidget {
      Liste finale  éléments = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];
      @passer outre
      Construction du widget (contexte) => GridView.builder (
        itemCount: elements.length,
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent (
          maxCrossAxisExtent: 130.0,
          crossAxisSpacing: 20,0,
          mainAxisSpacing: 20.0,
        ),
        itemBuilder: (context, i) => Carte (
          enfant: Centre (
            enfant: rembourrage (
              remplissage: EdgeInsets.all (8.0), enfant: texte (éléments [i])
            )
          )
        )
      );
    } 

    Sur des écrans plus grands, le corps lui-même peut être une ligne qui affiche deux widgets: le menu qui est limité à une largeur fixe, et le contenu remplissant le reste de l'écran.

    Sur les écrans plus petits, tout le corps serait le Contenu .

    Nous emballerons tout dans un SafeArea et un widget Centre parce que parfois les widgets de l'application Web Flutter, en particulier lors de l'utilisation des lignes et colonnes se retrouvent en dehors de la zone d'écran visible, et qui est fixé avec SafeArea et / ou Centre .

    Cela signifie que le corps de l'échafaudage sera le suivant:

     SafeArea (
      enfant: Centre (
        enfant: MediaQuery.of (contexte) .size.width <500? Contenu() :
        Rangée(
          enfants: [
            Container(
              width: 200.0,
              child: Menu()
            ),
            Container(
              width: MediaQuery.of(context).size.width-200.0,
              child: Content()
            )
          ]
        )
      )
    ) 

    Voici tout cela réuni :

    ( Grand aperçu )
     import 'package: flutter / material.dart';
    
    void main () => runApp (MyApp ());
    
    classe MyApp étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) => MaterialApp (
        home: HomePage ()
      );
    }
    
    
    classe HomePage étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) => Échafaudage (
        appBar: AppBar (titre: Texte ("test")),
        tiroir: MediaQuery.of (context) .size.width <500? Tiroir(
          enfant: Menu (),
        ) : nul,
        corps: SafeArea (
            enfant: Centre (
              enfant: MediaQuery.of (contexte) .size.width < 500 ? Content() :
              Row(
                children: [
                  Container(
                    width: 200.0,
                    child: Menu()
                  ),
                  Container(
                    width: MediaQuery.of(context).size.width-200.0,
                    child: Content()
                  )
                ]
              )
            )
        )
      );
    }
    
    class Menu extends StatelessWidget {
      @override
      Widget build(context) => ListView (
        enfants: [
          FlatButton(
            onPressed: () {},
              child: ListTile(
              leading: Icon(Icons.looks_one),
              title: Text("First Link"),
            )
          ),
          FlatButton(
            onPressed: () {},
              child: ListTile(
              leading: Icon(Icons.looks_two),
              title: Text("Second Link"),
            )
          )
        ]
      );
    }
    
    classe Content étend StatelessWidget {
      Liste finale  éléments = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];
      @passer outre
      Construction du widget (contexte) => GridView.builder (
        itemCount: elements.length,
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent (
          maxCrossAxisExtent: 130.0,
          crossAxisSpacing: 20,0,
          mainAxisSpacing: 20.0,
        ),
        itemBuilder: (context, i) => Carte (
          enfant: Centre (
            enfant: rembourrage (
              remplissage: EdgeInsets.all (8.0), enfant: texte (éléments [i])
            )
          )
        )
      );
    } 

    Il s'agit de la plupart des éléments dont vous aurez besoin en tant qu'introduction générale à l'interface utilisateur réactive dans Flutter. Une grande partie de son application dépendra de l'interface utilisateur spécifique de votre application, et il est difficile de déterminer exactement ce que vous pouvez faire pour rendre votre application réactive, et vous pouvez adopter de nombreuses approches en fonction de vos préférences. Maintenant, voyons comment nous pouvons faire un exemple plus complet dans une application réactive, en pensant aux éléments d'application courants et aux flux d'interface utilisateur.

    Mise en contexte: rendre une application réactive

    Jusqu'à présent, nous avons juste un écran. Développons cela en une application à deux écrans avec une navigation basée sur les URL!

    Création d'une page de connexion réactive

    Il y a de fortes chances que votre application dispose d'une page de connexion. Comment pouvons-nous rendre cela réactif?

    Les écrans de connexion sur les appareils mobiles sont assez similaires les uns aux autres. L'espace disponible n'est pas beaucoup; il s'agit généralement d'une colonne avec un rembourrage autour de ses widgets, et elle contient TextField pour taper un nom d'utilisateur et un mot de passe et un bouton pour se connecter. Ainsi, une page de connexion assez standard (bien qu'elle ne fonctionne pas, car cela nécessiterait, entre autres, une TextEditingController pour chaque TextField ) page de connexion pour une application mobile pourrait être la suivante: [19659073]Échafaud(
      corps: Conteneur (
        padding: const EdgeInsets.symmetric (
          vertical: 30,0, horizontal: 25,0
        ),
        enfant: Colonne (
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          enfants: [
    Text(« Welcome to the app, please log in »),
    TextField(
    decoration: InputDecoration(
    labelText: « username »
    )
    ),
    TextField(
    obscureText: true,
    decoration: InputDecoration(
    labelText: « password »
    )
    ),
    RaisedButton(
    color: Colors.blue,
    child: Text(« Log in », style: TextStyle(color: Colors.white)),
    onPressed: () {}
    )
    ]
        ),
      ),
    )

    Cela semble bien sur un appareil mobile, mais ces très larges TextField commencent à avoir l'air discordants sur une tablette, sans parler d'un écran plus grand. Cependant, nous ne pouvons pas simplement décider d'une largeur fixe parce que les téléphones ont des tailles d'écran différentes, et nous devons maintenir une certaine flexibilité.

    Par exemple, grâce à l'expérimentation, nous pourrions trouver que la largeur maximale devrait être de 500. Eh bien, nous définirions les contraintes de Container à 500 (j'ai utilisé un Container au lieu de Padding dans l'exemple précédent car je savais où J'allais avec ça) et nous sommes prêts à partir, non? Pas vraiment, car cela ferait coller les widgets de connexion sur le côté gauche de l'écran, ce qui pourrait être encore pire que de tout étirer. Donc, nous encapsulons dans un widget Centre comme ceci:

     Centre (
      enfant: conteneur (
        contraintes: BoxConstraints (maxWidth: 500),
        padding: const EdgeInsets.symmetric (
          vertical: 30,0, horizontal: 25,0
        ),
        enfant: colonne (/ * ...  * /)
      )
    ) 

    Cela semble déjà très bien, et nous n'avons même pas eu à utiliser un LayoutBuilder ou le MediaQuery.of (context) .size . Allons un peu plus loin pour que ce soit très beau, cependant. À mon avis, ce serait mieux si la partie de premier plan était en quelque sorte séparée de l'arrière-plan. Nous pouvons y parvenir en donnant une couleur d'arrière-plan à ce qui se trouve derrière le Container avec les widgets d'entrée, et en gardant le premier plan Container blanc. Pour le rendre un peu meilleur, empêchons le Container de s'étirer vers le haut et le bas de l'écran sur les gros appareils, lui donner des coins arrondis et lui donner une belle transition animée entre les deux dispositions. [19659010] Tout cela nécessite maintenant un LayoutBuilder et un conteneur externe afin à la fois de définir une couleur d'arrière-plan et d'ajouter du rembourrage tout autour du conteneur et pas seulement sur les côtés uniquement sur des écrans plus grands. De plus, pour que la modification de la quantité de remplissage soit animée, il suffit de transformer ce conteneur extérieur en un AnimatedContainer ce qui nécessite une durée pour l'animation, ce qui nécessite nous allons définir une demi-seconde, qui est Durée (millisecondes: 500) dans le code.

    Voici cet exemple d'une page de connexion réactive :

    ( Grand aperçu )
     La classe LoginPage étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        Échafaud(
          corps: LayoutBuilder (
            constructeur: (contexte, contraintes) {
              return AnimatedContainer (
                duration: Duration (millisecondes: 500),
                couleur: Colors.lightGreen [200],
                padding: contraintes.maxWidth < 500 ? EdgeInsets.zero : EdgeInsets.all(30.0),
                child: Center(
                  child: Container(
                    padding: EdgeInsets.symmetric(
                      vertical: 30.0, horizontal: 25.0
                    ),
                    constraints: BoxConstraints(
                      maxWidth: 500,
                    ),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(5.0),
                    ),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        Text("Welcome to the app, please log in"),
                        TextField(
                          decoration: InputDecoration(
                            labelText: "username"
                          )
                        ),
                        TextField(
                          obscureText: true,
                          decoration: InputDecoration(
                            labelText: "password"
                          )
                        ),
                        RaisedButton(
                          color: Colors.blue,
                          child: Text("Log in", style: TextStyle(color: Colors.white)),
                          onPressed: () {
                            Navigator.pushReplacement(
                              context,
                              MaterialPageRoute(
                                builder: (context) => HomePage ()
                              )
                            );
                          }
                        )
                      ]
                    ),
                  ),
                )
              );
            }
          )
       );
    } 

    Comme vous pouvez le voir, j'ai également modifié le RaisedButton onPressed en un rappel qui nous dirige vers un écran nommé HomePage (qui pourrait être, par exemple, la vue que nous avons construite précédemment avec un GridView et un menu ou un tiroir). Maintenant, cependant, c'est sur cette partie de la navigation que nous allons nous concentrer.

    Itinéraires nommés: rendre la navigation de votre application plus semblable à une application Web appropriée

    Une chose courante pour les applications Web est la possibilité de changer d'écran basé sur l'URL. Par exemple, aller à https: // appurl / login devrait vous donner quelque chose de différent de https: // appurl / somethingelse . Flutter, en fait, prend en charge les itinéraires nommés qui ont deux objectifs:

    1. Dans une application Web, ils ont exactement cette fonctionnalité que j'ai mentionnée dans la phrase précédente.
    2. Dans n'importe quelle application, ils permettent vous pouvez prédéfinir des itinéraires pour votre application et leur donner des noms, puis pouvoir y accéder simplement en spécifiant leur nom.

    Pour ce faire, nous devons changer le constructeur MaterialApp en un constructeur qui ressemble comme suit:

     MaterialApp (
      initialRoute: "/ login",
      itinéraires: {
        "/ login": (context) => LoginPage (),
        "/ home": (context) => HomePage ()
      }
    ); 

    Et puis nous pouvons passer à un autre itinéraire en utilisant Navigator.pushNamed (context, routeName) et Navigator.pushReplacementNamed (context, routeName) au lieu de ] Navigator.push (contexte, itinéraire) et Navigator.pushReplacement (contexte, itinéraire) .

    Voici que s'appliquait à l'application hypothétique que nous avions construite dans le reste de cet article. Vous ne pouvez pas vraiment voir les itinéraires nommés en action dans DartPad, vous devriez donc essayer cela sur votre propre machine avec flutter run ou consultez l'exemple en action :

    ( Grand aperçu )
     import 'package: flutter / material.dart';
    
    void main () => runApp (MyApp ());
    
    classe MyApp étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        MaterialApp (
          initialRoute: "/ login",
          itinéraires: {
            "/ login": (context) => LoginPage (),
            "/ home": (context) => HomePage ()
          }
        );
    }
    
    La classe LoginPage étend StatelessWidget {
      @passer outre
      Construction du widget (contexte) =>
        Échafaud(
          corps: LayoutBuilder (
            constructeur: (contexte, contraintes) {
              return AnimatedContainer (
                duration: Duration (millisecondes: 500),
                couleur: Colors.lightGreen [200],
                padding: contraintes.maxWidth < 500 ? EdgeInsets.zero : const EdgeInsets.all(30.0),
                child: Center(
                  child: Container(
                    padding: const EdgeInsets.symmetric(
                      vertical: 30.0, horizontal: 25.0
                    ),
                    constraints: BoxConstraints(
                      maxWidth: 500,
                    ),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(5.0),
                    ),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        Text("Welcome to the app, please log in"),
                        TextField(
                          decoration: InputDecoration(
                            labelText: "username"
                          )
                        ),
                        TextField(
                          obscureText: true,
                          decoration: InputDecoration(
                            labelText: "password"
                          )
                        ),
                        RaisedButton(
                          color: Colors.blue,
                          child: Text("Log in", style: TextStyle(color: Colors.white)),
                          onPressed: () {
                            Navigator.pushReplacementNamed(
                              context,
                              "/home"
                            );
                          }
                        )
                      ]
                    ),
                  ),
                )
              );
            }
          )
       );
    }
    
    
    class HomePage extends StatelessWidget {
      @override
      Widget build(context) => Échafaudage (
        appBar: AppBar (titre: Texte ("test")),
        tiroir: MediaQuery.of (context) .size.width <500? Tiroir(
          enfant: Menu (),
        ) : nul,
        corps: SafeArea (
            enfant: Centre (
              enfant: MediaQuery.of (contexte) .size.width < 500 ? Content() :
              Row(
                children: [
                  Container(
                    width: 200.0,
                    child: Menu()
                  ),
                  Container(
                    width: MediaQuery.of(context).size.width-200.0,
                    child: Content()
                  )
                ]
              )
            )
        )
      );
    }
    
    class Menu extends StatelessWidget {
      @override
      Widget build(context) => ListView (
        enfants: [
          FlatButton(
            onPressed: () {},
              child: ListTile(
              leading: Icon(Icons.looks_one),
              title: Text("First Link"),
            )
          ),
          FlatButton(
            onPressed: () {},
              child: ListTile(
              leading: Icon(Icons.looks_two),
              title: Text("Second Link"),
            )
          ),
          FlatButton(
            onPressed: () {Navigator.pushReplacementNamed(
              context, "/login");},
              child: ListTile(
              leading: Icon(Icons.exit_to_app),
              title: Text("Log Out"),
            )
          )
        ]
      );
    }
    
    classe Content étend StatelessWidget {
      Liste finale  éléments = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];
      @passer outre
      Construction du widget (contexte) => GridView.builder (
        itemCount: elements.length,
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent (
          maxCrossAxisExtent: 130.0,
          crossAxisSpacing: 20,0,
          mainAxisSpacing: 20.0,
        ),
        itemBuilder: (context, i) => Carte (
          enfant: Centre (
            enfant: rembourrage (
              remplissage: EdgeInsets.all (8.0), enfant: texte (éléments [i])
            )
          )
        )
      );
    } 

    En avant avec votre aventure Flutter

    Cela devrait vous donner une idée de ce que vous pouvez faire avec Flutter sur des écrans plus grands, en particulier sur le Web. C'est un cadre charmant, très facile à utiliser, et sa prise en charge multiplateforme extrême ne fait que le rendre plus essentiel pour apprendre et commencer à utiliser. Alors, allez-y et faites également confiance à Flutter pour les applications Web!

    Autres ressources

     Éditorial fracassant (ra, yk, il, al)




    Source link

    Revenir vers le haut