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 AndroidFlutter. Partie 2. Pour les développeurs iOSFlutter. Partie 3. Pour les développeurs de React NativeFlutter. Partie 4. Pour les développeurs WebFlutter. Partie 5. Pour les développeurs Xamarin.FormsContenu:
- Projet
- Views
- Async UI
- Layouts
- ListView
- Texte
- Plugins Flutter
- Code spécifique à la plateforme
- Débogage
- 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 {
@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(
title: new Text(widget.title),
),
body: new Center(
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 XAML
fichier?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 XAML
fichier .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 Content
l'élément ou des méthodes Add()
et Remove()
.Exemple:
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> {
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 FadeTo
ou 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 {
@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 :- Mappez les noms pour décrire l' itinéraire ;
- 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(),
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 assets
peut ê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.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.yaml
fichier: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: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('he', 'IL'),
],
)
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(
crossAxisCount: 2,
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 {
@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 {
@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 {
@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 {
@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 {
@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 platform
dans 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-s
ou 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:Stockage local
Question:
Comment stocker des key-value
donné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!