[Par les quais] Flutter. Partie 5. Pour les développeurs Xamarin.Forms

Il s'agit de la dernière partie d'une interprétation concise de la documentation Flutter qui sera utile aux développeurs Xamarin.Forms. Étant donné la situation actuelle, il est temps d'apprendre quelque chose de nouveau! Sous la coupe, vous pouvez trouver suffisamment d'informations pour évaluer si cela vaut la peine de passer d'un cadre multiplateforme à un autre et combien de temps cela prendra.



Si ces informations ne suffisent pas ou si vous avez de l'expérience en développement natif pour une plate-forme spécifique, je vous recommande de regarder dans d'autres parties:

Flutter. Partie 1. Pour les développeurs Android
Flutter. Partie 2. Pour les développeurs iOS
Flutter. Partie 3. Pour les développeurs de React Native
Flutter. Partie 4. Pour les développeurs Web
Flutter. Partie 5. Pour les développeurs Xamarin.Forms

Contenu:


  1. Projet

  2. Views



  3. Async UI





  4. Layouts



  5. ListView

  6. Texte

  7. Plugins Flutter

  8. Code spécifique à la plateforme

  9. Débogage

  10. Stockage local



Projet


Question:


Où est le point d'entrée?

Réponse:


Fonction main().

Différences:


Dans Xamarin.Forms, c'est le cas LoadApplication(new App());.

Exemple:


void main() {
  runApp(new MyApp());
}

Question:


Comment créer une page ou un élément ?

Réponse:


Flutter n'a aucun concept de page et d' élément en tant que tel. Tous les composants sont des widgets. Flutter a 2 types de widgets: StatelessWidget et StatefulWidget . Ils fonctionnent de la même manière, la seule différence est dans l'état de rendu.

Différences:


StatelessWidget a un état immuable. Convient pour afficher du texte, un logo, etc. Ceux. si l'élément à l'écran ne doit pas changer pendant toute la durée d'affichage, cela vous convient. Il peut également être utilisé comme conteneur pour les widgets avec état.

StatefulWidget a la classe State , qui stocke des informations sur l'état actuel. Si vous souhaitez modifier un élément à l'écran lors de l'exécution d'une action (une réponse est venue du serveur, l'utilisateur a cliqué sur un bouton, etc.) - c'est votre option.

Exemple:


StatelessWidget:
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set the appbar title.
        title: new Text(widget.title),
      ),
      body: new Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: new Icon(Icons.add),
      ),
    );
  }
}

Vues


Question:


Comment organiser les widgets? Quel est l'équivalent d'un XAMLfichier?

Réponse:


Dans Flutter, la mise en page se fait directement dans le code en utilisant l'arborescence des widgets.

Différence:


Dans Xamarin.Forms, la mise en page se fait le plus souvent dans un XAMLfichier .file. Flutter n'a pas d'équivalent.

Information additionnelle:


La liste des widgets peut être consultée ici .

Exemple:


@override
Widget build(BuildContext context) {
  return new Scaffold(
    appBar: new AppBar(
      title: new Text("Sample App"),
    ),
    body: new Center(
      child: new MaterialButton(
        onPressed: () {},
        child: new Text('Hello'),
        padding: new EdgeInsets.only(left: 10.0, right: 10.0),
      ),
    ),
  );
}

Question:


Comment ajouter ou supprimer un widget via du code?

Réponse:


En mettant à jour l'état du widget parent, puis en reconstruisant l'arborescence des widgets.

Différences:


Dans Xamarin.Forms, cela peut être fait en utilisant la propriété de Contentl'élément ou des méthodes Add()et Remove().

Exemple:


class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  // Default value for toggle
  bool toggle = true;
  void _toggle() {
    setState(() {
      toggle = !toggle;
    });
  }

  _getToggleChild() {
    if (toggle) {
      return new Text('Toggle One');
    } else {
      return new CupertinoButton(
        onPressed: () {},
        child: new Text('Toggle Two'),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sample App"),
      ),
      body: new Center(
        child: _getToggleChild(),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _toggle,
        tooltip: 'Update Text',
        child: new Icon(Icons.update),
      ),
    );
  }
}

Question:


Comment animer un widget?

Réponse:


Utilisation des classes Animation et AnimationController .

Différences:


Xamarin.Forms utilise ViewExtensions et des méthodes comme FadeToou TranslateTo.

Information additionnelle:


En savoir plus sur l'animation ici .

Exemple:


import 'package:flutter/material.dart';

void main() {
  runApp(new FadeAppTest());
}

class FadeAppTest extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Fade Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyFadeTest(title: 'Fade Demo'),
    );
  }
}

class MyFadeTest extends StatefulWidget {
  MyFadeTest({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyFadeTest createState() => new _MyFadeTest();
}

class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin {
  AnimationController controller;
  CurvedAnimation curve;

  @override
  void initState() {
    controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
    curve = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
          child: new Container(
              child: new FadeTransition(
                  opacity: curve,
                  child: new FlutterLogo(
                    size: 100.0,
                  )))),
      floatingActionButton: new FloatingActionButton(
        tooltip: 'Fade',
        child: new Icon(Icons.brush),
        onPressed: () {
          controller.forward();
        },
      ),
    );
  }
}

Question:


Comment dessiner sur l'écran?

Réponse:


Utilisation des classes CustomPaint et CustomPainter .

Différences:


Xamarin.Forms utilise un SkiaSharp tiers . Dans Flutter, Skia Canvas est utilisé directement à partir de la boîte.

Exemple:


import 'package:flutter/material.dart';

void main() => runApp(new MaterialApp(home: new DemoApp()));

class DemoApp extends StatelessWidget {
  Widget build(BuildContext context) => new Scaffold(body: new Signature());
}

class Signature extends StatefulWidget {
  SignatureState createState() => new SignatureState();
}

class SignatureState extends State<Signature> {
  List<Offset> _points = <Offset>[];
  Widget build(BuildContext context) {
    return new GestureDetector(
      onPanUpdate: (DragUpdateDetails details) {
        setState(() {
          RenderBox referenceBox = context.findRenderObject();
          Offset localPosition =
          referenceBox.globalToLocal(details.globalPosition);
          _points = new List.from(_points)..add(localPosition);
        });
      },
      onPanEnd: (DragEndDetails details) => _points.add(null),
      child: new CustomPaint(painter: new SignaturePainter(_points), size: Size.infinite),
    );
  }
}

class SignaturePainter extends CustomPainter {
  SignaturePainter(this.points);
  final List<Offset> points;
  void paint(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.black
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 5.0;
    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null && points[i + 1] != null)
        canvas.drawLine(points[i], points[i + 1], paint);
    }
  }
  bool shouldRepaint(SignaturePainter other) => other.points != points;
}

Question:


Comment changer la transparence?

Réponse:


Utilisation du widget Opacity .

Différences:


Xamarin.Forms utilise l' opacité de VisualElement . Dans Flutter, il vous suffit d'envelopper le widget souhaité dans Opacity .

Question:


Comment créer des widgets personnalisés?

Réponse:


Composez-les à l'intérieur d'un (au lieu de l'héritage).

Différences:


Dans Xamarin.Forms, vous pouvez hériter du VisualElement qui nous intéresse et ajouter votre propre logique. Dans Flutter, un widget est toujours hérité de StatelessWidget et StatefulWidget . Ceux. vous devez créer un nouveau widget et utiliser l'ensemble des widgets nécessaires en tant que paramètres ou champs.

Exemple:


class CustomButton extends StatelessWidget {
  final String label;

  CustomButton(this.label);

  @override
  Widget build(BuildContext context) {
    return new RaisedButton(onPressed: () {}, child: new Text(label));
  }
}

La navigation


Question:


Comment naviguer entre les écrans?

Réponse:


Pour naviguer entre les écrans, les classes Navigator et Route sont utilisées .

Différences:


Xamarin.Forms utilise la NavigationPage .

Flutter a deux méthodes de navigation similaires à NavigationPage :

  1. Mappez les noms pour décrire l' itinéraire ;
  2. Accédez directement à Route .

Navigator peut faire pousser () ou pop () vers l'itinéraire que vous spécifiez.

Exemple:


void main() {
  runApp(CupertinoApp(
    home: MyAppHome(), // becomes the route named '/'
    routes: <String, WidgetBuilder> {
      '/a': (BuildContext context) => MyPage(title: 'page A'),
      '/b': (BuildContext context) => MyPage(title: 'page B'),
      '/c': (BuildContext context) => MyPage(title: 'page C'),
    },
  ));
}

Navigator.of(context).pushNamed('/b');

Question:


Comment naviguer vers une application tierce?

Réponse:


Utilisation d'implémentations natives via MethodChannel ou le plugin url_launcher .

Interface utilisateur asynchrone


Question:


Quel est l'équivalent de Device.BeginInvokeOnMainThread () ? Comment exécuter du code de manière asynchrone?

Réponse:


Dart implémente un modèle d'exécution monothread qui s'exécute sur des isolats . Pour une exécution asynchrone, utilisez async / wait, que vous connaissez depuis C #.

Exemple:


Répondre à la demande et renvoyer le résultat de la mise à jour de l'interface utilisateur:
loadData() async {
  String dataURL = "https://jsonplaceholder.typicode.com/posts";
  http.Response response = await http.get(dataURL);
  setState(() {
    widgets = json.decode(response.body);
  });
}

Lorsque la réponse à la demande est reçue, vous devez appeler la méthode setState () pour redessiner l'arborescence du widget avec les nouvelles données.

Un exemple de chargement et de mise à jour des données dans un ListView :
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  List widgets = [];

  @override
  void initState() {
    super.initState();

    loadData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView.builder(
          itemCount: widgets.length,
          itemBuilder: (BuildContext context, int position) {
            return getRow(position);
          }));
  }

  Widget getRow(int i) {
    return Padding(
      padding: EdgeInsets.all(10.0),
      child: Text("Row ${widgets[i]["title"]}")
    );
  }

  loadData() async {
    String dataURL = "https://jsonplaceholder.typicode.com/posts";
    http.Response response = await http.get(dataURL);
    setState(() {
      widgets = json.decode(response.body);
    });
  }
}

Question:


Comment faire des requêtes réseau?

Réponse:


Utilisation du plugin http .

Exemple:


Connectez la dépendance via pubspec.yaml:
dependencies:
  ...
  http: ^0.11.3+16

Enquête:
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
[...]
  loadData() async {
    String dataURL = "https://jsonplaceholder.typicode.com/posts";
    http.Response response = await http.get(dataURL);
    setState(() {
      widgets = json.decode(response.body);
    });
  }
}

Question:


Comment afficher la progression de longues opérations?

Réponse:


Utilisation de ProgressIndicator .

Différences:


Dans Xamarin.Forms, cela peut être fait directement en plaçant un indicateur de progression dans XAML.

Exemple:


import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(new SampleApp());
}

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  List widgets = [];

  @override
  void initState() {
    super.initState();
    loadData();
  }

  showLoadingDialog() {
    return widgets.length == 0;
  }

  getBody() {
    if (showLoadingDialog()) {
      return getProgressDialog();
    } else {
      return getListView();
    }
  }

  getProgressDialog() {
    return new Center(child: new CircularProgressIndicator());
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("Sample App"),
        ),
        body: getBody());
  }

  ListView getListView() => new ListView.builder(
      itemCount: widgets.length,
      itemBuilder: (BuildContext context, int position) {
        return getRow(position);
      });

  Widget getRow(int i) {
    return new Padding(padding: new EdgeInsets.all(10.0), child: new Text("Row ${widgets[i]["title"]}"));
  }

  loadData() async {
    String dataURL = "https://jsonplaceholder.typicode.com/posts";
    http.Response response = await http.get(dataURL);
    setState(() {
      widgets = json.decode(response.body);
    });
  }
}

Structure et ressources du projet


Question:


Où stocker les ressources de différentes résolutions?

Réponse:


Dans assets.

Différences:


Xamarin.Forms ne dispose pas d'un stockage unifié pour les ressources de plate-forme, vous devez donc les stocker séparément dans des dossiers de plate-forme. Il y a un Flutter assets. Le dossier assetspeut être situé n'importe où dans le projet, surtout, écrivez le chemin d'accès dans le fichier pubspec.yaml.

Information additionnelle:


Comparaison des tailles de ressources graphiques dans Android et Flutter.
Qualificateur de densité AndroidRapport de pixels de flottement
ldpi0,75x
mdpi1.0x
hdpi1,5x
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4,0x
Exemple de disposition des ressources:
images/my_icon.png       // Base: 1.0x image
images/2.0x/my_icon.png  // 2.0x image
images/3.0x/my_icon.png  // 3.0x image

Un exemple de chemin dans un pubspec.yamlfichier:
assets:
 - images/my_icon.jpeg

Un exemple d'utilisation de AssetImage :
return AssetImage("images/a_dot_burr.jpeg");

Exemple d'utilisation directe asset:
@override
Widget build(BuildContext context) {
  return Image.asset("images/my_image.png");
}

Question:


Où stocker les cordes? Comment les localiser?

Réponse:


Flutter n'a pas de place spécifique pour stocker les chaînes pour le moment. Il est proposé de les stocker sous forme de champs statiques dans une classe distincte. Pour la localisation, des plugins sont utilisés, par exemple flutter_localizations ou l10n .

Différences:


Xamarin.Forms utilise un fichier resx.

Exemple:


Espace de rangement:
class Strings {
  static String welcomeMessage = "Welcome To Flutter";
}

En utilisant:
new Text(Strings.welcomeMessage)

Localisation:
dependencies:
  # ...
  flutter_localizations:
    sdk: flutter
  intl: "^0.15.6"

import 'package:flutter_localizations/flutter_localizations.dart';

new MaterialApp(
 localizationsDelegates: [
   // Add app-specific localization delegate[s] here.
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', 'US'), // English
    const Locale('he', 'IL'), // Hebrew
    // ... other locales the app supports
  ],
  // ...
)

Question:


Où est le dossier de projet?

Réponse:


Flutter n'a pas de fichier de projet pour ouvrir ce projet dans l'environnement de développement. Le fichier similaire le plus proche - pubspec.yaml- contient des dépendances sur les plugins et les détails du projet.

Cycle de vie de l'application


Question:


Comment gérer les événements du cycle de vie?

Réponse:


Utilisation de la méthode WidgetsBinding et didChangeAppLifecycleState () .

Information additionnelle:


Flutter utilise FlutterActivity dans le code Android et FlutterAppDelegate dans iOS, en raison de ce moteur Flutter rend les changements d'état de traitement aussi discrets que possible. Mais si vous avez encore besoin de travailler selon l'état, le cycle de vie est légèrement différent:
  • inactif - cette méthode est uniquement dans iOS, dans Android il n'y a pas d'analogue;
  • en pause - similaire à onPause () dans Android;
  • reprise - similaire à onPostResume () dans Android;
  • suspension - similaire à onStop dans Android, dans iOS il n'y a pas d'analogue.

Voir la documentation AppLifecycleStatus pour plus de détails .

Exemple:


import 'package:flutter/widgets.dart';

class LifecycleWatcher extends StatefulWidget {
  @override
  _LifecycleWatcherState createState() => _LifecycleWatcherState();
}

class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver {
  AppLifecycleState _lastLifecycleState;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    setState(() {
      _lastLifecycleState = state;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_lastLifecycleState == null)
      return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr);

    return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.',
        textDirection: TextDirection.ltr);
  }
}

void main() {
  runApp(Center(child: LifecycleWatcher()));
}

Disposition


Question:


Quel est l'analogue de StackLayout ?

Réponse:


L'analogue de StackLayout avec orientation verticale est Colonne et horizontal - Ligne .

Exemple:


Colonne:
@override
Widget build(BuildContext context) {
  return new Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      new Text('Column One'),
      new Text('Column Two'),
      new Text('Column Three'),
      new Text('Column Four'),
    ],
  );
}

Rangée:
@override
Widget build(BuildContext context) {
  return new Row(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      new Text('Row One'),
      new Text('Row Two'),
      new Text('Row Three'),
      new Text('Row Four'),
    ],
  );
}

Question:


Quel est l'analogue de la grille ?

Réponse:


Le GridView .

Exemple:


GridView.count(
  // Create a grid with 2 columns. If you change the scrollDirection to
  // horizontal, this would produce 2 rows.
  crossAxisCount: 2,
  // Generate 100 widgets that display their index in the List
  children: List.generate(100, (index) {
    return Center(
      child: Text(
        'Item $index',
        style: Theme.of(context).textTheme.headline,
      ),
    );
  }),
);

Question:


Quel est l'analogue de ScrollView ?

Réponse:


L'analogue le plus proche est SingleChildScrollView . Mais Flutter utilise le plus souvent ListView pour créer du contenu qui rampe .

Exemple:


SingleChildScrollView:
@override
Widget build(BuildContext context) {
  return new SingleChildScrollView(
    child: new Text('Long Content'),
  );
}

ListView:
@override
Widget build(BuildContext context) {
  return new ListView(
    children: <Widget>[
      new Text('Row One'),
      new Text('Row Two'),
      new Text('Row Three'),
      new Text('Row Four'),
    ],
  );
}

Manipulation des gestes


Question:


Comment gérer les clics?

Réponse:


Si le widget prend en charge la méthode onPressed, vous pouvez gérer le clic en l'utilisant. Sinon, cela peut être fait via le GestureDetector .

Exemple:


onPressed:
@override
Widget build(BuildContext context) {
  return new RaisedButton(
      onPressed: () {
        print("click");
      },
      child: new Text("Button"));
}

GestureDetector:
class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Center(
      child: new GestureDetector(
        child: new FlutterLogo(
          size: 200.0,
        ),
        onTap: () {
          print("tap");
        },
      ),
    ));
  }
}

Question:


Comment gérer les gestes?

Réponse:


Utilisation de GestureDetector . Ils peuvent gérer les actions suivantes:

Robinet



Tapez deux fois



Appui long



Traînée verticale



Glissement horizontal



Exemple:


AnimationController controller;
CurvedAnimation curve;

@override
void initState() {
  controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
  curve = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
}

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Center(
          child: new GestureDetector(
            child: new RotationTransition(
                turns: curve,
                child: new FlutterLogo(
                  size: 200.0,
                )),
            onDoubleTap: () {
              if (controller.isCompleted) {
                controller.reverse();
              } else {
                controller.forward();
              }
            },
        ),
    ));
  }
}

ListView et adaptateurs


Question:


Quel est l'analogue de ListView ?

Réponse:


Le ListView .

Différences:


Dans Xamarin.Forms, vous devez créer un ViewCell et (le plus souvent) un DataTemplateSelector et les transmettre au ListView . Dans Flutter, il vous suffit de passer une liste de widgets à afficher.

Exemple:


import 'package:flutter/material.dart';

void main() {
  runApp(new SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sample App"),
      ),
      body: new ListView(children: _getListData()),
    );
  }

  _getListData() {
    List<Widget> widgets = [];
    for (int i = 0; i < 100; i++) {
      widgets.add(new Padding(padding: new EdgeInsets.all(10.0), child: new Text("Row $i")));
    }
    return widgets;
  }
}

Question:


Comment déterminer quel élément a été cliqué?

Réponse:


Dans Flutter, un widget d'élément doit gérer son clic lui-même.

Différences:


Xamarin.Forms utilise le plus souvent ItemTapped .

Exemple:


import 'package:flutter/material.dart';

void main() {
  runApp(new SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sample App"),
      ),
      body: new ListView(children: _getListData()),
    );
  }

  _getListData() {
    List<Widget> widgets = [];
    for (int i = 0; i < 100; i++) {
      widgets.add(new GestureDetector(
        child: new Padding(
            padding: new EdgeInsets.all(10.0),
            child: new Text("Row $i")),
        onTap: () {
          print('row tapped');
        },
      ));
    }
    return widgets;
  }
}

Question:


Comment mettre à jour dynamiquement un ListView ?

Réponse:


Actualisez la liste des données et appelez setState().

Différences:


Xamarin.Forms utilise un ItemsSource pour cette . Dans Flutter, après le setState()widget sera redessiné à nouveau.

Exemple:


import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  List widgets = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 100; i++) {
      widgets.add(getRow(i));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView(children: widgets),
    );
  }

  Widget getRow(int i) {
    return GestureDetector(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Text("Row $i"),
      ),
      onTap: () {
        setState(() {
          widgets = List.from(widgets);
          widgets.add(getRow(widgets.length + 1));
          print('row $i');
        });
      },
    );
  }
}

Information additionnelle:


Pour créer une liste, il est recommandé d'utiliser ListView.Builder .

Exemple:


import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  List widgets = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 100; i++) {
      widgets.add(getRow(i));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView.builder(
        itemCount: widgets.length,
        itemBuilder: (BuildContext context, int position) {
          return getRow(position);
        },
      ),
    );
  }

  Widget getRow(int i) {
    return GestureDetector(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Text("Row $i"),
      ),
      onTap: () {
        setState(() {
          widgets.add(getRow(widgets.length + 1));
          print('row $i');
        });
      },
    );
  }
}

Texte


Question:


Comment utiliser des polices personnalisées?

Réponse:


Le fichier de police que vous avez juste besoin de mettre dans un dossier (pensez à un nom pour vous-même) et indiquez le chemin d'accès pubspec.yaml.

Exemple:


fonts:
   - family: MyCustomFont
     fonts:
       - asset: fonts/MyCustomFont.ttf
       - style: italic

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("Sample App"),
    ),
    body: Center(
      child: Text(
        'This is a custom font text',
        style: TextStyle(fontFamily: 'MyCustomFont'),
      ),
    ),
  );
}

Question:


Comment styliser des widgets de texte?

Réponse:


Utilisation de paramètres:

  • Couleur;
  • décoration;
  • décorationCouleur;
  • decorationStyle;
  • famille de polices;
  • taille de police;
  • le style de police;
  • fontWeight;
  • hashCode;
  • la taille;
  • hériter;
  • l'espacement des lettres;
  • textBaseline;
  • wordSpacing.

Question:


Quel est l'équivalent de Placeholder ?

Réponse:


La hintText propriété de InputDecoration .

Exemple:


body: new Center(
  child: new TextField(
    decoration: new InputDecoration(hintText: "This is a hint"),
  )
)

Question:


Comment afficher les erreurs de validation?

Réponse:


Tout de même avec InputDecoration et son état.

Exemple:


class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  String _errorText;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: Center(
        child: TextField(
          onSubmitted: (String text) {
            setState(() {
              if (!isEmail(text)) {
                _errorText = 'Error: This is not an email';
              } else {
                _errorText = null;
              }
            });
          },
          decoration: InputDecoration(hintText: "This is a hint", errorText: _getErrorText()),
        ),
      ),
    );
  }

  _getErrorText() {
    return _errorText;
  }

  bool isEmail(String emailString) {
    String emailRegexp =
        r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';

    RegExp regExp = RegExp(emailRegexp);

    return regExp.hasMatch(emailString);
  }
}

Plugins Flutter


Question:


Comment accéder au GPS?

Réponse:


Utilisation du plugin geolocator .

Question:


Comment accéder à la caméra?

Réponse:


Utilisation du plugin image_picker .

Question:


Comment se connecter via Facebook?

Réponse:


Utilisation du plugin flutter_facebook_login .

Question:


Comment utiliser Firebase?

Réponse:


Firebase prend en charge les plugins propriétaires Flutter :

Code spécifique à la plateforme


Question:


Comment déterminer sur quelle plateforme s'exécute le code?

Réponse:


Utilisation de la classe de champ platformdans Theme ou la classe Platform .

Exemple:


Champ platform:
if (Theme.of(context).platform == TargetPlatform.iOS) {
  return 'iOS';
} else if (Theme.of(context).platform == TargetPlatform.android) {
  return 'android';
} else if (Theme.of(context).platform == TargetPlatform.fuchsia) {
  return 'fuchsia';
} else {
  return 'not recognised ';
}

Classe de plate-forme:
if (Platform.isIOS) {
  return 'iOS';
} else if (Platform.isAndroid) {
  return 'android';
} else if (Platform.isFuchsia) {
  return 'fuchsia';
} else {
  return 'not recognised ';
}

Question:


Comment appeler du code de plateforme natif?

Réponse:


Via MethodChannel .

Information additionnelle:


Plus de détails ici .

Débogage


Question:


Quels sont les outils pour déboguer l'application?

Réponse:


DevTools .

Question:


Comment faire hot reload?

Réponse:


Si l'application a été lancée depuis IntelliJ IDE, Android Studio ou VSCode, alors en combinant ⌘s/ctrl-sou en cliquant sur l'icône hot reload. Si démarré à partir du terminal, puis en entrant une lettre r.

Question:


Comment accéder au menu développeur dans l'application?

Réponse:


Si le lancement a été effectué à partir de l'EDI, utilisez les outils IDE. Si depuis la console, utilisez h.

Information additionnelle:


Liste complète des commandes:

ActeÉquipe dans le terminalFonctions et champs
Hiérarchie des widgetswdebugDumpApp ()
Arbre de rendutdebugDumpRenderTree ()
CouchesLdebugDumpLayerTree ()
AccessibilitéS (ordre de traversée) ou U (ordre de test de coup inverse)debugDumpSemantics ()
Inspecteur de widgetsjeWidgetsApp.showWidgetInspectorOverride
Afficher les lignes de constructionpdebugPaintSizeEnabled
Simulation de différents OSodefaultTargetPlatform
PerformancePWidgetsApp. showPerformanceOverlay
Capture d'écran flutter.pngs
Clôture de l'applicationq

Stockage local


Question:


Comment stocker des key-valuedonnées dans l'application?

Réponse:


Utilisation du plugin shared_preferences .

Différences:


Dans Xamarin.Forms est utilisé Xam.Plugins.Settings.

Exemple:


Dépendance de connexion:
dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^0.4.3

En utilisant:
SharedPreferences prefs = await SharedPreferences.getInstance();
_counter = prefs.getInt('counter');
prefs.setInt('counter', ++_counter);
setState(() {
  _counter = _counter;
});

Question:


Comment stocker des données complexes?

Réponse:


Utiliser des plugins de base de données comme sqflite ou hive .

Voici peut-être les réponses aux questions de base. Ceci conclut la série d'interprétations. J'espère qu'ils ont été utiles à tous les développeurs intéressés par ce framework. Peut-être avez-vous même commencé à écrire sur Flutter et vous avez recruté dans une communauté amicale de développeurs Flutter. Et je vais penser à de nouveaux articles afin de développer la communauté et de faire du monde des applications un meilleur endroit. Que vos formulaires ne cassent pas Xamarin!

All Articles