Après une longue pause, je continuerai à parler du cadre Flutter populaire dans un format de questions et réponses. Vous pouvez trouver le premier article pour les développeurs Android
ici , et aujourd'hui, il y aura du matériel utile pour les développeurs pour iOS.
Si vous avez peu de temps pour une étude indépendante et approfondie de la documentation, mais que vous voulez comprendre ce que Flutter est bon et comment l'utiliser, jetez un œil sous le chat.
Flutter. Partie 1. Pour les développeurs AndroidFlutter. Partie 2. Pour les développeurs iOSFlutter. Partie 3. Pour les développeurs natifs de ReactFlutter. Partie 4. Pour les développeurs WebFlutter. Partie 5. Pour les développeurs Xamarin.Forms
Contenu:
- Vues
- La navigation
- Filetage et asynchronicité
- Structure et ressources du projet
- ViewControllers
- Disposition
- Gestes et gestion des événements tactiles
- Style d'application
- Formulaire de saisie
- Plugins Flutter
- Bases de données et stockage local
- Notifications
Vues
Question:
Qu'est-ce que l'
analogue UIView dans Flutter?
La réponse est:
WidgetDifférences:
UIView est en fait ce qui sera
affiché à l'écran. SetNeedsDisplay () est appelé pour afficher les modifications.
Widget - une description de ce qui sera à l'écran. Car le changement est créé à nouveau.
Information complémentaire:
Flutter comprend la bibliothèque
Cupertino Widgets . Il contient des widgets qui mettent en œuvre
les directives Apple Design .
Question:
Comment mettre à jour l'affichage des widgets?
La réponse est:
Utilisation de
StatefulWidget et de son
état . 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. C'est-à-dire 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 l'état 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.
Un exemple:
1) StatelessWidget - Texte
Text( 'I like Flutter!', style: TextStyle(fontWeight: FontWeight.bold), );
2) StatefulWidget - lorsque vous cliquez sur le bouton (FloatingActionButton), le texte du widget Texte passe de
J'aime Flutter à
Flutter est génial! import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Question:
Comment mettre en page un écran avec des widgets? Où est le
storyboard ?
La réponse est:
Flutter n'a pas de
Storyboard . Tout est composé dans l'arborescence des widgets directement dans le code.
Un exemple:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: CupertinoButton( onPressed: () { setState(() { _pressedCount += 1; }); }, child: Text('Hello'), padding: EdgeInsets.only(left: 10.0, right: 10.0), ), ), ); }
Tous les widgets par défaut de Flutter peuvent être affichés dans le
catalogue de widgets .
Question:
Comment ajouter ou supprimer un composant dans la mise en page pendant que l'application est en cours d'exécution?
La réponse est:
Grâce à une fonction qui renverra le widget souhaité en fonction de l'état.
Différences:
Sur iOS, vous pouvez ajouter addSubview () ou supprimerFromSuperview (). Dans Flutter, ce n'est pas possible car les widgets sont inchangés. Seul leur état peut changer.
Un exemple:
Changez le texte en bouton en cliquant sur FloatingActionButton.
class SampleApp extends StatelessWidget {
Question:
Comment animer des widgets?
La réponse est:
Utilisation de la classe
AnimationController , qui est la descendante de la classe abstraite
Animation <T> . En plus de démarrer l'animation, il peut la mettre en pause, revenir en arrière, l'arrêter et la jouer dans la direction opposée. Fonctionne avec
Ticker , qui signale un rafraîchissement de l'écran.
Différences:
Sur iOS, vous pouvez animer une vue en utilisant animate (withDuration: animations :). Dans Flutter, l'animation doit être écrite en code à l'aide de AnimationController.
Information complémentaire:
Vous pouvez en savoir plus dans les
widgets Animation & Motion , le
didacticiel Animations et la
vue d'ensemble Animations .
Un exemple:
Animation en fondu du logo Flutter.
class SampleApp extends StatelessWidget {
Question:
Comment utiliser
CoreGraphics ?
La réponse est:
Flutter utilise l'API Canvas sur le moteur de bas niveau
Skia au lieu de CoreGraphics. Android utilise une API Canvas similaire.
Information complémentaire:
Flutter a deux classes pour dessiner sur Canvas:
CustomPaint et
CustomPainter . Le second implémente votre algorithme de rendu.
En savoir plus ici:
StackOverflowUn exemple:
class SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset> points; void paint(Canvas canvas, Size size) { var paint = 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; } class Signature extends StatefulWidget { SignatureState createState() => SignatureState(); } class SignatureState extends State<Signature> { List<Offset> _points = <Offset>[]; Widget build(BuildContext context) { return GestureDetector( onPanUpdate: (DragUpdateDetails details) { setState(() { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); _points = List.from(_points)..add(localPosition); }); }, onPanEnd: (DragEndDetails details) => _points.add(null), child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite), ); } }
Question:
Comment changer la transparence des widgets?
La réponse est:
Enveloppez dans le widget
Opacity .
Différences:
Sur iOS, toutes les vues ont .opacity ou .alpha. Dans Flutter, cette option remplace le widget wrapper.
Question:
Comment créer des widgets personnalisés?
La réponse est:
Composez des widgets à l'intérieur d'un (au lieu de l'héritage).
Différences:
Dans iOS, vous pouvez hériter de la vue qui nous intéresse et ajouter votre propre logique. Dans Flutter, un widget est toujours hérité de StatelessWidget ou StatefulWidget. C'est-à-dire vous devez créer un nouveau widget et l'utiliser comme l'ensemble de widgets dont vous avez besoin en tant que paramètres ou champs.
Un exemple:
class CustomButton extends StatelessWidget { final String label; CustomButton(this.label); @override Widget build(BuildContext context) { return RaisedButton(onPressed: () {}, child: Text(label)); } } @override Widget build(BuildContext context) { return Center( child: CustomButton("Hello"), ); }
La navigation
Question:
Comment implémenter la navigation entre les écrans dans Flutter?
La réponse est:
La navigation entre les écrans utilise les classes
Navigator et
Route .
Différences:
Flutter n'a pas de concepts tels que UIViewController et UINavigationController. Il existe Navigator (Navigator) et Routes (routes). Navigator est similaire à UINavigationController en principe. Il peut faire
push () ou
pop () sur l'itinéraire que vous spécifiez. Route est une sorte d'UIViewController, mais dans Flutter, il est habituel de le comparer avec un écran ou une page.
Flutter a deux méthodes de navigation:
- Décrire une carte avec des noms de route
- Accédez directement à Route.
Un exemple:
void main() { runApp(CupertinoApp( home: MyAppHome(),
Question:
Comment naviguer vers une application tierce?
La réponse est:
Soit en interagissant avec la couche iOS de l'application via
MethodChannel , soit en utilisant le plug-in de
lancement d'URL .
Question:
Comment faire revenir pop dans iOS ViewController?
La réponse est:
En appelant SystemNavigator.pop ().
Information complémentaire:
SystemNavigator.pop () du code Dart appelle le code suivant dans iOS:
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController; if ([viewController isKindOfClass:[UINavigationController class]]) { [((UINavigationController*)viewController) popViewControllerAnimated:NO]; }
Si ce n'est pas ce dont vous avez besoin, vous pouvez effectuer votre implémentation via
MethodChannel .
Filetage et asynchronicité
Question:
Comment écrire du code asynchrone dans Flutter?
La réponse est:
Dart implémente un modèle d'exécution monothread qui s'exécute sur des
isolats . L'exécution asynchrone utilise async / wait, que vous connaissez peut-être avec les coroutines C #, JavaScript ou Kotlin.
Un 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 de nouvelles données.
Un exemple:
Chargement et 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 exécuter du code dans un thread d'arrière-plan?
La réponse est:
Comme mentionné ci-dessus - en utilisant async / wait et isolation (Isolate).
Différences:
Hors de la boîte sur iOS, vous pouvez utiliser Operation avec une redéfinition possible des méthodes. Dans Flutter «prêt à l'emploi», il vous suffit d'utiliser asynchrone / attendre, Dart s'occupe du reste.
Un exemple:
Ici, la méthode dataLoader () est isolée. Isolément, vous pouvez exécuter des opérations lourdes telles que l'analyse de gros JSON, le chiffrement, le traitement d'image, etc.
loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort);
Question:
Comment faire des requêtes réseau dans Flutter?
La réponse est:
Flutter a son propre
package HTTP .
Un exemple:
Pour utiliser le package HTTP, ajoutez-le en tant que dépendance dans pubspec.yaml:
dependencies: ... http: ^0.11.3+16
Pour exécuter la demande, appelez wait dans la fonction asynchrone http.get ():
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 montrer les progrès?
La réponse est:
Utilisation du widget
ProgressIndicator .
Un exemple:
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(); } showLoadingDialog() { return widgets.length == 0; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => 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); }); } }
Structure et ressources du projet
Question:
Où stocker les ressources de différentes résolutions?
La réponse est:
En actifs.
Différences:
Dans iOS, les ressources graphiques ont Images.xcasset, qui se trouvent dans le dossier des ressources. Flutter n'a que des atouts. Le dossier de ressources peut être situé n'importe où dans le projet, et surtout, écrivez le chemin d'accès dans le fichier pubspec.yaml.
Information complémentaire:
Les tailles des ressources graphiques dans iOS et Flutter sont identiques et suivent le format basé sur la densité.
Emplacement 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
Chemin dans le fichier pubspec.yaml:
assets: - images/my_icon.png
Utilisation de
AssetImage :
return AssetImage("images/a_dot_burr.jpeg");
Utilisation directe de l'actif:
@override Widget build(BuildContext context) { return Image.asset("images/my_image.png"); }
Question:
Où stocker les cordes? Comment les localiser?
La réponse est:
Conserver dans des champs statiques. Localisez à l'aide du
package intl .
Un exemple:
class Strings { static String welcomeMessage = "Welcome To Flutter"; } Text(Strings.welcomeMessage)
Question:
Quelle est la contrepartie de CocoaPods? Comment ajouter des dépendances?
La réponse est:
pubspec.yaml.
Information complémentaire:
Flutter délègue la génération aux constructeurs natifs Android et iOS. Voir une liste de toutes les bibliothèques populaires pour Flutter au
Pub .
ViewControllers
Question:
Quel est l'équivalent de
ViewController dans Flutter?
La réponse est:
Tout dans Flutter est des widgets. Le rôle de ViewController pour travailler avec l'interface utilisateur est joué par les widgets. Et le rôle de la navigation, comme mentionné dans le paragraphe sur la navigation, est Navigateur et Route.
Question:
Comment gérer les événements du cycle de vie?
La réponse est:
Utilisation de la
méthode WidgetsBinding et
didChangeAppLifecycleState () .
Information complémentaire:
Flutter utilise FlutterAppDelegate dans le code natif et le moteur Flutter rend la gestion des changements d'état aussi discrète que possible. Mais si vous avez encore besoin de travailler selon l'état, le cycle de vie est légèrement différent:
- inactif - l'application est inactive et ne reçoit aucune entrée d'utilisateur. Cet état est uniquement sous iOS, dans Android il n'y a pas d'analogue;
- en pause - l'application est actuellement invisible pour l'utilisateur, ne répond pas aux entrées de l'utilisateur, mais fonctionne en arrière-plan;
- reprise - l'application est visible et répond aux entrées de l'utilisateur;
- suspension - application en cours d'arrêt. Cet état est uniquement sous Android, dans iOS il n'y a pas d'analogue.
Ceci est décrit plus en détail dans la
documentation AppLifecycleStatus .
Un 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'équivalent de
UITableView et
UICollectionView ?
La réponse est:
ListViewUn exemple:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Question:
Comment savoir quel élément de la liste a été cliqué?
La réponse est:
Le widget, qui est un élément de la liste, doit gérer le clic dessus.
Différences:
Dans iOS, la méthode séparée tableView: didSelectRowAtIndexPath: en est responsable. Dans Flutter, l'élément de liste doit être encapsulé dans un widget qui gère les clics, tel que
GestureDetector .
Question:
Comment mettre à jour dynamiquement un
ListView ?
La réponse est:
Actualisez la liste de données et appelez setState ().
Différences:
Sur iOS, vous devez mettre à jour les données et appeler la méthode reloadData. Dans Flutter, après setState (), le widget sera à nouveau redessiné.
Un exemple:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Information complémentaire:
Pour créer une liste, il est recommandé d'utiliser
ListView.Builder .
Un exemple:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Question:
Quel est l'analogue d'
UIScrollView ?
La réponse est:
ListView avec des widgets.
Un exemple:
@override Widget build(BuildContext context) { return ListView( children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); }
Information complémentaire:
Plus de détails
ici .
Gestes et gestion des événements tactiles
Question:
Comment ajouter un écouteur onClick pour un widget dans Flutter?
La réponse est:
Si le widget prend en charge les clics, alors dans onPressed (). Sinon, alors dans onTap ().
Un exemple:
Dans onPressed ():
@override Widget build(BuildContext context) { return RaisedButton( onPressed: () { print("click"); }, child: Text("Button"), ); }
Dans onTap ():
class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: FlutterLogo( size: 200.0, ), onTap: () { print("tap"); }, ), ), ); } }
Question:
Comment gérer d'autres gestes sur les widgets?
La réponse est:
Utilisation de
GestureDetector . Ils peuvent gérer les actions suivantes:
Appuyez sur
Appuyez deux fois
Appui long
Traînée verticale
Glissement horizontal
Un exemple:
Traitement sur Double Tap:
AnimationController controller; CurvedAnimation curve; @override void initState() { controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: RotationTransition( turns: curve, child: FlutterLogo( size: 200.0, )), onDoubleTap: () { if (controller.isCompleted) { controller.reverse(); } else { controller.forward(); } }, ), ), ); } }
Style d'application
Question:
Comment utiliser le thème (Thème) dans l'application?
La réponse est:
Utiliser le widget MaterialApp ou WidgetApp comme racine dans l'application.
Un exemple:
class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, textSelectionColor: Colors.red ), home: SampleAppPage(), ); } }
Question:
Comment utiliser des polices personnalisées?
La réponse est:
Il vous suffit de mettre le fichier de police dans le dossier (pensez au nom vous-même) et d'indiquer le chemin d'accès à celui-ci dans pubspec.yaml.
Un 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?
La réponse est:
Utilisation de paramètres:
- la couleur;
- décoration;
- décorationCouleur;
- decorationStyle;
- fontFamily;
- fontSize;
- fontStyle;
- fontWeight;
- hashCode;
- hauteur;
- hériter;
- letterSpacing;
- textBaseline;
- wordSpacing.
Formulaire de saisie
Question:
Comment obtenir le résultat de la saisie utilisateur?
La réponse est:
Utilisation de
TextEditingController .
Un exemple:
class _MyFormState extends State<MyForm> {
:
Retrieve the value of a text field .
:
hint
TextInput ?
La réponse est:
InputDecoration , .
Un exemple:
body: Center( child: TextField( decoration: InputDecoration(hintText: "This is a hint"), ), )
:
?
La réponse est:
—
InputDecoration .
Un exemple:
class SampleApp extends StatelessWidget {
Flutter
:
GPS?
La réponse est:
geolocator .
:
?
La réponse est:
image_picker .
:
Facebook?
La réponse est:
flutter_facebook_login .
:
Firebase?
La réponse est:
Firebase
Flutter first party plugins :
:
() ?
La réponse est:
Flutter EventBus . :
developing packages and plugins .
:
UserDefault?
La réponse est:
Shared_Preferences plugin ( Shared Preferences Android ).
Un exemple:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { runApp( MaterialApp( home: Scaffold( body: Center( child: RaisedButton( onPressed: _incrementCounter, child: Text('Increment Counter'), ), ), ), ), ); } _incrementCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); int counter = (prefs.getInt('counter') ?? 0) + 1; print('Pressed $counter times.'); prefs.setInt('counter', counter); }
:
Core Data ?
La réponse est:
SQFlite .
Notifications
:
push-?
La réponse est:
Firebase_Messaging .
. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . . Apple Store!