Flutter. Avantages et inconvénients



Tout d'abord, parlons un peu de ce qu'est Flutter. Il s'agit d'un cadre pour créer des applications mobiles à partir de Google. Il est multi-plateforme et vous permet de compiler le projet créé pour 3 systèmes d'exploitation:
  • Android
  • iOS
  • Fuchsia

De plus, pour le dernier OS - Fuchsia - c'est le seul moyen de créer une application.
Flutter depuis longtemps, depuis 2015, n'a été présenté qu'en versions alpha et bêta. La première version stable est sortie le 4 décembre 2018.


Flutter est activement promu par Google, gagnant progressivement en popularité et, très probablement, continuera à évincer les autres outils de développement multiplateforme actuellement utilisés (React Native, Xamarin), surtout si Fuchsia est largement distribué. Étant donné que Google positionne ce système d'exploitation en remplacement d'Android, Flutter remplacera tôt ou tard le développement natif d'Android. Par conséquent, les perspectives et le développement actif sont les principaux avantages de Flutter.


+ Perspective et développement actif


Voyons comment cela fonctionne.


Dans le langage de programmation Dart, une application mobile est créée avec une description de l'interface graphique et toute la logique de travail. Le résultat du travail est ajouté à l'application native, comme les images, les polices et autres (bien sûr, ce processus est automatisé).


Dans le même temps, dans la partie native de l'application, un seul écran est créé où la machine virtuelle Dart est chargée, qui exécute Flutter.


Notez que l'un des inconvénients de Flutter découle d'ici:


- Le package d'installation final est plus grand, car la machine virtuelle Dart y est ajoutée.


Ainsi, il y a des fichiers Flutter et il y a des machines virtuelles qui sont ajoutées en fonction de ce qui se compile - iOS ou Android.


La machine virtuelle possède son propre moteur graphique, elle dessine l'interface de l'application avec toutes les transitions entre écrans, dialogues, fragments, etc. En cela, le développement sous Flutter est significativement différent du développement avec Xamarin et React Native, qui utilisent de vrais composants Android et iOS. Dans le cas d'entre eux, il est impossible d'utiliser des composants spécifiques à la plate-forme (s'il y a un tel besoin, vous devez créer deux versions de l'interface utilisateur). Lorsque vous choisissez un design avec Flutter, il suffit de se concentrer sur une seule plate-forme (par exemple, Android). Lors de la création d'un projet pour iOS, vous verrez une interface Android standard. Cela aura l'air un peu étrange et inattendu, mais assez fonctionnel (plus tard, l'interface peut être améliorée).


+ Propre moteur graphique (pas besoin de faire une interface séparément pour Android et iOS)


Maintenant sur les impressions.


Lors du portage de plusieurs applications d'Android vers Flutter, nous avons noté quelques différences, qui peuvent être considérées à la fois comme un plus et un moins.


La première chose qui attire votre attention est un moyen de créer des écrans, qui est considérablement différent de celui utilisé sur Android et iOS. Sous Android, la logique et l'interface sont séparées: la logique est définie par le code, et l'interface est définie par la disposition en xml. Sur Flutter, tout est réglé à l'aide de code. Bien qu'ici, un style spécial soit utilisé pour l'interface - les éléments d'interface sont créés imbriqués les uns dans les autres. C'est un peu comme la mise en page, une manière très similaire fonctionne dans React Native. Cependant, il n'y a aucune possibilité d'accès direct aux éléments. Pour changer quelque chose à l'écran, vous devez soit mettre à jour la totalité de l'écran, soit utiliser des contrôleurs spéciaux ajoutés à l'avance au widget lors de sa création.


- L'interface est créée à l'aide de code, ce qui rend la ligne entre la logique et la conception beaucoup plus mince.


D'un autre côté, cette approche facilite la division des écrans en composants séparés. En fait, n'importe quel bloc d'éléments d'interface imbriqués peut être déplacé vers un widget séparé en seulement quelques étapes, ce qui est beaucoup plus facile que de créer une vue et des fragments personnalisés.


+ L'interface est facilement divisée en modules séparés


Les deux dernières remarques méritent probablement d'être examinées. Pour ce faire, nous allons écrire une application simple qui illustre certaines des fonctionnalités de Flutter. Ce sera une application avec une barre de navigation standard et une barre d'onglets.


Faisons trois onglets:


1) Tout d'abord - avec du texte et des curseurs pour ajuster la taille et la couleur du texte
2) Ajoutez une image téléchargeable à la seconde (avec indicateur de progression)
3) À la troisième place un exemple de liste




Supposons également que nous n'ayons pas initialement divisé l'interface d'application en onglets séparés. Dans Flutter, vous pouvez implémenter cet écran sans utiliser de fragments. Bien sûr, une telle partition est toujours souhaitable, mais supposons qu'ils aient oublié de le faire, ou que la conception ait changé, après quoi le développement a été poursuivi par l'inertie d'une classe.

Considérez maintenant le code source qui implémente cette disposition:


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: 'Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } 

Ce fragment de code est standard pour presque toutes les applications Flutter (il est créé avec le projet).


MyApp est une classe de l'application elle-même, qui décrit les paramètres généraux lors de la création de MaterialApp: nom de l'application, polices, couleurs et styles. L'écran principal de l'application est également indiqué ici (pour nous, c'est MyHomePage).


Faisons une note importante: dans les widgets Flutter sont divisés en deux types:


1) StatefulWidget
2) StatelessWidget


Deux classes sont nécessaires pour décrire StatefulWidget: la classe du widget lui-même et la classe de son état (dans lequel le travail principal aura lieu).


StatelessWidget est décrit par une classe avec un état fixe, et il ne peut être modifié qu'en recréant à partir du widget principal. Par conséquent, pour nos besoins, StatefulWidget est requis.


Considérez maintenant _MyHomePageState:


 class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: <Widget>[ 

Pour faciliter la perception, un onglet avec du texte est marqué en rouge, un onglet avec une image en vert, un onglet de liste en bleu et un menu de navigation en jaune. Comme vous pouvez le voir, l'interface est décrite comme un ensemble de widgets (et leurs tableaux) intégrés les uns aux autres:










Fonctions utilisées:
  void _onTapped(int index) { setState(() { _currentIndex = index; }); } void _setTextStyle( {double size = -1, double r = -1, double g = -1, double b = -1}) { setState(() { if (size > 0) { _size = size; } if (r > 0) { _r = r; } if (g > 0) { _g = g; } if (b > 0) { _b = b; } }); } } 

Examinons-les plus en détail:


onTapped - une fonction appelée lors du basculement d'un onglet dans le menu du bas. Il appelle la fonction spéciale setState, qui vous permet de mettre à jour le widget actuel avec de nouvelles données (et nous avons mis à jour la variable _currentIndex).


Voyons où cela s'applique:


 body: <Widget>[    ][_currentIndex] 

Ici, nous avons affaire à un tableau, d'où l'utilisation de _currentIndex, l'une des options de disposition d'écran est sélectionnée, et elle est remplacée comme l'un des onglets.


Vient ensuite la fonction _setTextStyle. Il a une annonce très inhabituelle pour les langages de type C.


 void _setTextStyle({double size = -1, double r = -1, double g = -1,double b = -1}) 

Les arguments lui sont transmis non pas comme une liste, mais comme un tableau. C'est l'une des fonctionnalités très intéressantes de Dart, qui vous permet de créer des fonctions avec un nombre variable d'arguments beaucoup plus finement que ce qui se passe dans la plupart des autres langages.


Puisque chaque argument est nommé, nous pouvons les prendre dans un ordre aléatoire. Par exemple:


 _setTextStyle(size: 24, b: 255) 

Décomposons la classe grand écran en widgets. Il est préférable de décomposer par éléments logiques, dans notre cas ce sont des onglets. Grâce aux fonctionnalités de Flutter, pour cela, il nous suffit de prendre les fragments de code responsables de chaque onglet et de les transférer avec la logique dans des classes séparées en utilisant la méthode de construction.


Premier onglet:


 class TextWidget extends StatefulWidget { @override _TextWidgetState createState() => _TextWidgetState(); } class _TextWidgetState extends State<TextWidget> { double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text("Example String", style: TextStyle( fontSize: _size, color: Color.fromRGBO(_r.toInt(), _g.toInt(), _b.toInt(), 1))), Container(constraints: BoxConstraints.expand(height: 32.0)), Slider( label: "${_size.toInt()} sp", value: _size, min: 10, max: 48, divisions: 38, activeColor: Colors.black, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(size: val)), Slider( label: _r.toInt().toString(), value: _r, min: 0, max: 255, divisions: 255, activeColor: Colors.red, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(r: val), ), Slider( label: _g.toInt().toString(), value: _g, min: 0, max: 255, divisions: 255, activeColor: Colors.green, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(g: val), ), Slider( label: _b.toInt().toString(), value: _b, min: 0, max: 255, divisions: 256, activeColor: Colors.blue, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(b: val), ), ], ); } } 

Comme le widget doit être mis à jour (méthode _setTextStyle), nous utilisons StatefulWidget.
Aucune mise à jour n'est nécessaire pour les deux onglets suivants, nous utiliserons donc StatelessWidget.


Deuxième onglet:


 class ImageWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Stack( children: <Widget>[ Center(child: CircularProgressIndicator()), Center( child: FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: 'https://picsum.photos/250?image=9', ), ), ], ); } } 

Troisième onglet:


 class ListWidget extends StatelessWidget { @override Widget build(BuildContext context) { return ListView.builder( itemCount: 25, itemBuilder: (BuildContext context, int index) { return Container( child: Text( 'entry $index', style: TextStyle(color: Colors.white), ), margin: EdgeInsets.all(16.0), padding: EdgeInsets.all(16.0), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.all( Radius.circular(16.0), ), ), ); }, ); } } 

Code d'état de l'écran principal modifié:


 class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), actions: <Widget>[ IconButton(icon: Icon(Icons.navigate_next), onPressed: next) ], ), body: <Widget>[ TextWidget(), ImageWidget(), ListWidget(), ][_currentIndex], bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: _onTapped, items: [ BottomNavigationBarItem( icon: new Icon(Icons.text_format), title: new Text('Text'), ), BottomNavigationBarItem( icon: new Icon(Icons.image), title: new Text('Image'), ), BottomNavigationBarItem( icon: Icon(Icons.list), title: Text('ListView'), ) ], )); } 

Ainsi, nous divisons facilement un grand écran en un petit écran et trois petits widgets. Vous pouvez remarquer que dans Flutter, les écrans ne sont pas conceptuellement différents des widgets (plus précisément, les widgets assument à la fois les fonctions d'activité, les fragments et les vues personnalisées). Cette fonctionnalité est très pratique lorsque l'application a besoin d'une vue plein écran de n'importe quel élément - pour cela, vous pouvez utiliser nos widgets avec un raffinement minimal.


Et pourtant, il existe des différences minimes entre un widget utilisé comme écran et un widget standard. L'élément racine du widget écran doit être un objet Scaffold (vous permet d'ajouter appBar, bottomNavigationBar, floatingActionButton, tiroir, etc.).


Les widgets classiques n'ont pas cette limitation, car en utilisant la méthode de construction, ils seront intégrés dans l'écran principal, où Scaffold est déjà disponible.


Heureusement, l'ajout de Scaffold à un widget standard n'affecte pas ses performances.


Vous pouvez également ajouter SafeArea (pour fournir un retrait pour la barre d'état). La conversion simple suivante est obtenue:


De:


 @override Widget build(BuildContext context) { return []; } 

À:


 @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: [] ), ); } 

Eh bien, revenons maintenant à la discussion des avantages et des inconvénients de Flutter.


Flutter a récemment été publié, les bugs sont donc assez courants. Cela est particulièrement visible lors de la mise à jour de Flutter - certaines bibliothèques commencent à fonctionner avec des erreurs.


- Instabilité (vient de quitter la version bêta)


De toute évidence, lorsque vous utilisez le nouveau cadre, vous avez beaucoup moins de bibliothèques à votre disposition qu'avec le développement natif Android / iOS. Cependant, il existe encore beaucoup de bibliothèques pour Flutter, et elles continuent d'apparaître à grande vitesse. Par exemple, de nombreuses bibliothèques ont été ajoutées au second semestre 2018, apparemment, en préparation de la première version stable, et les bibliothèques les plus importantes (Google Analytics, Firebase, Maps, etc.) existaient avant cela.


- Moins de bibliothèques que pour le développement natif
+ Les bibliothèques les plus importantes sont déjà là, de nouvelles sortent constamment


Il est temps de faire le point! Rappelons tous les avantages et les inconvénients, en organisant les éléments des avantages les plus importants aux inconvénients les plus importants:


+ Multiplateforme
+ Perspective et développement actif
+ Les bibliothèques les plus importantes sont déjà là, de nouvelles sortent constamment
+ Propre moteur graphique
+ L'interface est facilement divisée en modules séparés


- Le package d'installation final est plus grand, car la machine virtuelle Dart y est ajoutée
- L'interface est créée à l'aide de code, ce qui rend la ligne entre la logique et la conception beaucoup plus mince
- Moins de bibliothèques (et d'informations) que pour le développement natif
- Instabilité (vient de quitter la version bêta)


Merci de votre attention!

Source: https://habr.com/ru/post/fr441766/


All Articles