Flutter - Introduction aux mises en page

Puisque le concept de base de Flutter est que tout est widget , Flutter intègre une fonctionnalité de mise en page d'interface utilisateur dans les widgets eux-mêmes. Flutter fournit un grand nombre de widgets spécialement conçus comme Container, Center, Align , etc., uniquement dans le but de mettre en page l'interface utilisateur. Les widgets créés en composant d'autres widgets utilisent normalement des widgets de mise en page. Laissez l'utilisation apprendre le concept de disposition Flutter dans ce chapitre.

Type de widgets de mise en page

Les widgets de mise en page peuvent être regroupés en deux catégories distinctes en fonction de leur enfant -

  • Widget supportant un seul enfant
  • Widget prenant en charge plusieurs enfants

Apprenons à la fois le type de widgets et ses fonctionnalités dans les sections à venir.

Widgets enfant unique

Dans cette catégorie, les widgets n'auront qu'un seul widget comme enfant et chaque widget aura une fonctionnalité de mise en page spéciale.

Par exemple, le widget Centre centre simplement son widget enfant par rapport à son widget parent et le widget Conteneur offre une flexibilité complète pour le placer enfant à n'importe quel endroit donné à l'intérieur en utilisant différentes options telles que le remplissage, la décoration, etc.,

Les widgets enfants uniques sont d'excellentes options pour créer des widgets de haute qualité ayant une seule fonctionnalité telle que bouton, étiquette, etc.,

Le code pour créer un bouton simple à l'aide du widget Container est le suivant -

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

Ici, nous avons utilisé deux widgets - un widget Container et un widget Text . Le résultat du widget est un bouton personnalisé comme indiqué ci-dessous -

Voyons quelques-uns des widgets de mise en page pour enfant unique les plus importants fournis par Flutter -

  • Padding- Utilisé pour organiser son widget enfant par le remplissage donné. Ici, le remplissage peut être fourni par la classe EdgeInsets .

  • Align- Alignez son widget enfant sur lui-même en utilisant la valeur de la propriété alignement . La valeur de la propriété d' alignement peut être fournie par la classe FractionalOffset . La classe FractionalOffset spécifie les décalages en termes de distance à partir du coin supérieur gauche.

Certaines des valeurs possibles des décalages sont les suivantes -

  • FractionalOffset (1.0, 0.0) représente le coin supérieur droit.

  • FractionalOffset (0.0, 1.0) représente le coin inférieur gauche.

Un exemple de code sur les décalages est présenté ci-dessous -

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox - Il met à l'échelle le widget enfant, puis le positionne en fonction de l'ajustement spécifié.

  • AspectRatio - Il tente de dimensionner le widget enfant au rapport hauteur / largeur spécifié

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

Notre application hello world utilise des widgets de mise en page basés sur des matériaux pour concevoir la page d'accueil. Modifions notre application hello world pour créer la page d'accueil en utilisant des widgets de mise en page de base comme spécifié ci-dessous -

  • Container - Widget conteneur générique, enfant unique, basé sur une boîte avec alignement, remplissage, bordure et marge ainsi que de riches fonctionnalités de style.

  • Center - Widget conteneur enfant simple et unique, qui centre son widget enfant.

Le code modifié du widget MyHomePage et MyApp est comme ci-dessous -

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

Ici,

  • Le widget de conteneur est le widget de niveau supérieur ou racine. Le conteneur est configuré à l'aide de la propriété decoration et padding pour mettre en page son contenu.

  • BoxDecoration a de nombreuses propriétés comme la couleur, la bordure, etc., pour décorer le widget Conteneur et ici, la couleur est utilisée pour définir la couleur du conteneur.

  • le remplissage du widget Container est défini à l'aide de la classe dgeInsets , qui offre la possibilité de spécifier la valeur de remplissage.

  • Center est le widget enfant du widget Container . Encore une fois, Text est l'enfant du widget Centre . Le texte est utilisé pour afficher le message et le centre est utilisé pour centrer le message texte par rapport au widget parent, Container .

Le résultat final du code donné ci-dessus est un exemple de mise en page comme indiqué ci-dessous -

Widgets enfants multiples

Dans cette catégorie, un widget donné aura plus d'un widget enfant et la disposition de chaque widget est unique.

Par exemple, le widget Row permet la disposition de ses enfants dans le sens horizontal, tandis que le widget Column permet de disposer ses enfants dans le sens vertical. En composant Row et Column , un widget avec n'importe quel niveau de complexité peut être construit.

Apprenons quelques-uns des widgets fréquemment utilisés dans cette section.

  • Row - Permet de disposer ses enfants de manière horizontale.

  • Column - Permet de disposer ses enfants de manière verticale.

  • ListView - Permet d'organiser ses enfants sous forme de liste.

  • GridView - Permet d'agencer ses enfants en galerie.

  • Expanded - Utilisé pour que les enfants du widget Ligne et Colonne occupent la zone maximale possible.

  • Table - Widget basé sur une table.

  • Flow - Widget basé sur le flux.

  • Stack - Widget basé sur la pile.

Application de mise en page avancée

Dans cette section, apprenons à créer une interface utilisateur complexe de liste de produits avec une conception personnalisée à l'aide de widgets de mise en page enfants simples et multiples.

Pour cela, suivez la séquence ci-dessous -

  • Créez une nouvelle application Flutter dans le studio Android, product_layout_app .

  • Remplacez le code main.dart par le code suivant -

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: 'Flutter Demo', theme: ThemeData( 
         primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • Nous avons créé le widget MyHomePage en étendant StatelessWidget au lieu de StatefulWidget par défaut , puis avons supprimé le code correspondant.

  • Maintenant, créez un nouveau widget, ProductBox selon la conception spécifiée comme indiqué ci-dessous -

  • Le code de la ProductBox est le suivant.

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • Veuillez observer ce qui suit dans le code -

  • ProductBox a utilisé quatre arguments comme spécifié ci-dessous -

    • name - Nom du produit

    • description - Description du produit

    • prix - Prix du produit

    • image - Image du produit

  • ProductBox utilise sept widgets intégrés comme spécifié ci-dessous -

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBox est conçu en utilisant le widget mentionné ci-dessus. La disposition ou la hiérarchie du widget est spécifiée dans le diagramme ci-dessous -

  • Maintenant, placez une image factice (voir ci-dessous) pour les informations sur le produit dans le dossier assets de l'application et configurez le dossier assets dans le fichier pubspec.yaml comme indiqué ci-dessous -

assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png

iPhone.png

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

Enfin, utilisez le widget ProductBox dans le widget MyHomePage comme spécifié ci-dessous -

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • Ici, nous avons utilisé ProductBox comme enfants du widget ListView .

  • Le code complet (main.dart) de l'application de mise en page du produit (product_layout_app) est le suivant -

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: 'Flutter Demo', theme: ThemeData(
            primarySwatch: Colors.blue,
         ), 
         home: MyHomePage(title: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

La sortie finale de l'application est la suivante -