[An den Docks] Flattern. Teil 5. Für Xamarin.Forms-Entwickler

Dies ist der letzte Teil einer präzisen Interpretation der Flutter-Dokumentation , die für Xamarin.Forms-Entwickler nützlich sein wird. Angesichts der aktuellen Situation ist es jetzt an der Zeit, etwas Neues zu lernen! Unter dem Schnitt finden Sie genügend Informationen, um zu beurteilen, ob es sich lohnt, von einem plattformübergreifenden Framework zu einem anderen zu wechseln, und wie lange dies dauern wird.



Wenn diese Informationen nicht ausreichen oder Sie Erfahrung in der nativen Entwicklung für eine bestimmte Plattform haben, empfehle ich, in anderen Teilen

nachzuschauen : Flattern. Teil 1. Für Android-Entwickler
Flutter. Teil 2. Für iOS-Entwickler
Flutter. Teil 3. Für Entwickler von React Native
Flutter. Teil 4. Für Flutter- Webentwickler
. Teil 5. Für Xamarin.Forms-Entwickler

Inhalt:


  1. Projekt

  2. Views



  3. Async UI





  4. Layouts



  5. ListView

  6. Text

  7. Flatter Plugins

  8. Plattformspezifischer Code

  9. Debuggen

  10. Lokaler Speicher



Projekt


Frage:


Wo ist der Einstiegspunkt?

Antworten:


Funktion main().

Unterschiede:


In Xamarin.Forms ist dies LoadApplication(new App());.

Beispiel:


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

Frage:


Wie erstelle ich eine Seite oder ein Element ?

Antworten:


Flutter hat kein Konzept von Seite und Element als solchem. Alle Komponenten sind Widgets. Flutter hat zwei Arten von Widgets: StatelessWidget und StatefulWidget . Sie funktionieren auf die gleiche Weise, der einzige Unterschied besteht im Rendering-Status.

Unterschiede:


StatelessWidget hat einen unveränderlichen Zustand. Geeignet zum Anzeigen von Text, Logo usw. Jene. Sollte sich das Element auf dem Bildschirm während der gesamten Anzeigezeit nicht ändern, passt es zu Ihnen. Es kann auch als Container für Stateful Widgets verwendet werden.

StatefulWidget verfügt über die State- Klasse , in der Informationen zum aktuellen Status gespeichert werden . Wenn Sie ein Element auf dem Bildschirm ändern möchten, während Sie eine Aktion ausführen (eine Antwort kam vom Server, der Benutzer hat auf eine Schaltfläche geklickt usw.), ist dies Ihre Option.

Beispiel:


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),
      ),
    );
  }
}

Ansichten


Frage:


Wie arrangiere ich Widgets? Was entspricht einer XAMLDatei?

Antworten:


In Flutter erfolgt das Layout direkt im Code mithilfe des Widget-Baums.

Unterschied:


In Xamarin.Forms wird das Layout meistens in einer XAML.file erstellt. Flattern hat kein Äquivalent.

Weitere Informationen:


Die Liste der Widgets kann hier eingesehen werden .

Beispiel:


@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),
      ),
    ),
  );
}

Frage:


Wie füge ich ein Widget über Code hinzu oder entferne es?

Antworten:


Durch Aktualisieren des Status des übergeordneten Widgets und anschließendes Neuerstellen des Widgetbaums.

Unterschiede:


In Xamarin.Forms kann dies mithilfe der Eigenschaft des ContentElements oder der Methoden Add()und erfolgen Remove().

Beispiel:


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),
      ),
    );
  }
}

Frage:


Wie animiere ich ein Widget?

Antworten:


Verwenden der Klassen Animation und AnimationController .

Unterschiede:


Xamarin.Forms verwendet ViewExtensions und Methoden wie FadeTooder TranslateTo.

Weitere Informationen:


Lesen Sie mehr über Animation hier .

Beispiel:


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();
        },
      ),
    );
  }
}

Frage:


Wie zeichne ich auf dem Bildschirm?

Antworten:


Verwenden der Klassen CustomPaint und CustomPainter .

Unterschiede:


Xamarin.Forms verwendet SkiaSharp eines Drittanbieters . In Flutter wird Skia Canvas direkt aus der Box verwendet.

Beispiel:


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;
}

Frage:


Wie kann man die Transparenz ändern?

Antworten:


Verwenden des Deckkraft- Widgets .

Unterschiede:


Xamarin.Forms nutzt die Opazität von VisualElement . In Flutter müssen Sie nur das gewünschte Widget in Deckkraft einschließen .

Frage:


Wie erstelle ich benutzerdefinierte Widgets?

Antworten:


Verfassen Sie sie in einem (anstelle der Vererbung).

Unterschiede:


In Xamarin.Forms können Sie von dem für uns interessanten VisualElement erben und Ihre eigene Logik hinzufügen. In Flutter wird ein Widget immer von StatelessWidget und StatefulWidget geerbt . Jene. Sie müssen ein neues Widget erstellen und die darin enthaltenen erforderlichen Widgets als Parameter oder Felder verwenden.

Beispiel:


class CustomButton extends StatelessWidget {
  final String label;

  CustomButton(this.label);

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

Navigation


Frage:


Wie navigiere ich zwischen Bildschirmen?

Antworten:


Zum Navigieren zwischen Bildschirmen werden die Klassen Navigator und Route verwendet .

Unterschiede:


Xamarin.Forms verwendet die Navigationsseite .

Flutter verfügt über zwei Navigationsmethoden, die NavigationPage ähneln :

  1. Ordnen Sie die Namen zu, um die Route zu beschreiben .
  2. Navigieren Sie direkt zu Route .

Navigator kann Push () oder Pop () zu der von Ihnen angegebenen Route ausführen.

Beispiel:


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');

Frage:


Wie navigiere ich zu einer Drittanbieteranwendung?

Antworten:


Verwenden nativer Implementierungen über MethodChannel oder das url_launcher- Plugin .

Async ui


Frage:


Was entspricht Device.BeginInvokeOnMainThread () ? Wie führe ich Code asynchron aus?

Antworten:


Dart implementiert ein Single-Threaded-Ausführungsmodell, das auf Isolates ausgeführt wird . Verwenden Sie für die asynchrone Ausführung async / await, mit dem Sie aus C # vertraut sind.

Beispiel:


Erfüllen der Anforderung und Zurückgeben des Ergebnisses für die Aktualisierung der Benutzeroberfläche:
loadData() async {
  String dataURL = "https://jsonplaceholder.typicode.com/posts";
  http.Response response = await http.get(dataURL);
  setState(() {
    widgets = json.decode(response.body);
  });
}

Wenn die Antwort auf die Anforderung empfangen wird, müssen Sie die Methode setState () aufrufen , um den Widget-Baum mit den neuen Daten neu zu zeichnen.

Ein Beispiel für das Laden und Aktualisieren von Daten in einer 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);
    });
  }
}

Frage:


Wie mache ich Netzwerkanfragen?

Antworten:


Verwenden des http- Plugins .

Beispiel:


Verbinden Sie die Abhängigkeit über pubspec.yaml:
dependencies:
  ...
  http: ^0.11.3+16

Anfrage:
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);
    });
  }
}

Frage:


Wie kann der Fortschritt langer Operationen angezeigt werden?

Antworten:


Mit Progress .

Unterschiede:


In Xamarin.Forms kann dies direkt durch Platzieren einer Fortschrittsanzeige in erfolgen XAML.

Beispiel:


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);
    });
  }
}

Projektstruktur und Ressourcen


Frage:


Wo können Ressourcen mit unterschiedlichen Auflösungen gespeichert werden?

Antworten:


In assets.

Unterschiede:


Xamarin.Forms verfügt nicht über einen einheitlichen Speicher für Plattformressourcen, daher müssen Sie diese separat in Plattformordnern speichern. Es gibt ein Flattern assets. Der Ordner assetskann sich an einer beliebigen Stelle im Projekt befinden. Schreiben Sie vor allem den Pfad in die Datei pubspec.yaml.

Weitere Informationen:


Vergleich der Größe von Grafikressourcen in Android und Flutter.
Android Density QualifierFlatterpixelverhältnis
ldpi0,75x
mdpi1,0x
hdpi1,5x
xhdpi2,0x
xxhdpi3.0x
xxxhdpi4.0x
Beispiel für ein Ressourcenlayout:
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

Ein Beispiel für einen Pfad in einer pubspec.yamlDatei:
assets:
 - images/my_icon.jpeg

Ein Beispiel für die Verwendung von AssetImage :
return AssetImage("images/a_dot_burr.jpeg");

Beispiel für die direkte Verwendung asset:
@override
Widget build(BuildContext context) {
  return Image.asset("images/my_image.png");
}

Frage:


Wo können Zeichenfolgen gespeichert werden? Wie lokalisiere ich sie?

Antworten:


Flutter hat momentan keinen bestimmten Ort zum Speichern von Saiten. Es wird vorgeschlagen, sie als statische Felder in einer separaten Klasse zu speichern. Plugins werden zur Lokalisierung verwendet, zum Beispiel flutter_localizations oder l10n .

Unterschiede:


Xamarin.Forms verwendet eine Datei resx.

Beispiel:


Lager:
class Strings {
  static String welcomeMessage = "Welcome To Flutter";
}

Verwenden von:
new Text(Strings.welcomeMessage)

Lokalisierung:
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
  ],
  // ...
)

Frage:


Wo ist die Projektdatei?

Antworten:


Flutter verfügt nicht über eine Projektdatei, um dieses Projekt in der Entwicklungsumgebung zu öffnen. Die nächstgelegene ähnliche Datei - pubspec.yaml- enthält Abhängigkeiten von Plugins und Projektdetails.

Anwendungslebenszyklus


Frage:


Wie gehe ich mit Lebenszyklusereignissen um?

Antworten:


Verwenden der WidgetsBinding- und didChangeAppLifecycleState () -Methode .

Weitere Informationen:


Flutter verwendet FlutterActivity in Android-Code und FlutterAppDelegate in iOS. Aus diesem Grund macht die Flutter-Engine Änderungen des Verarbeitungsstatus so unauffällig wie möglich. Wenn Sie jedoch je nach Zustand noch etwas arbeiten müssen, ist der Lebenszyklus etwas anders:
  • inaktiv - diese Methode ist nur in iOS, in Android gibt es kein Analogon;
  • pausiert - ähnlich wie onPause () in Android;
  • wieder aufgenommen - ähnlich wie bei onPostResume () in Android;
  • Aussetzen - ähnlich wie bei onStop in Android gibt es in iOS kein Analogon.

Weitere Informationen finden Sie in der AppLifecycleStatus-Dokumentation .

Beispiel:


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()));
}

Layouts


Frage:


Was ist das Analogon von StackLayout ?

Antworten:


Das Analogon von StackLayout mit vertikaler Ausrichtung ist Column und mit horizontaler Zeile .

Beispiel:


Säule:
@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'),
    ],
  );
}

Reihe:
@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'),
    ],
  );
}

Frage:


Was ist das Analogon des Gitters ?

Antworten:


Die GridView .

Beispiel:


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,
      ),
    );
  }),
);

Frage:


Was ist das Analogon von ScrollView ?

Antworten:


Das nächstgelegene Analogon ist SingleChildScrollView . Am häufigsten verwendet Flutter jedoch ListView , um Inhalte zu erstellen, die gecrawlt werden .

Beispiel:


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

Listenansicht:
@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'),
    ],
  );
}

Gestenhandhabung


Frage:


Wie gehe ich mit Klicks um?

Antworten:


Wenn das Widget die Methode unterstützt onPressed, können Sie den Klick damit verarbeiten. Andernfalls kann dies über den GestureDetector erfolgen .

Beispiel:


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");
        },
      ),
    ));
  }
}

Frage:


Wie gehe ich mit Gesten um?

Antworten:


Verwenden des GestureDetector . Sie können die folgenden Aktionen ausführen:

Zapfhahn



Doppeltippen



Lange drücken



Vertikaler Widerstand



Horizontales Ziehen



Beispiel:


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 und Adapter


Frage:


Was ist das Analogon von ListView ?

Antworten:


Die ListView .

Unterschiede:


In Xamarin.Forms müssen Sie eine ViewCell und (meistens) einen DataTemplateSelector erstellen und an ListView übergeben . In Flutter müssen Sie nur eine Liste der anzuzeigenden Widgets übergeben.

Beispiel:


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;
  }
}

Frage:


Wie kann man feststellen, auf welches Element geklickt wurde?

Antworten:


In Flutter muss ein Element-Widget seinen Klick selbst verarbeiten.

Unterschiede:


Xamarin.Forms verwendet am häufigsten ItemTapped .

Beispiel:


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;
  }
}

Frage:


Wie aktualisiere ich eine ListView dynamisch ?

Antworten:


Aktualisieren Sie die Datenliste und rufen Sie an setState().

Unterschiede:


Xamarin.Forms verwendet hierfür eine ItemsSource . In Flutter wird das setState()Widget nach dem erneuten Zeichnen neu gezeichnet.

Beispiel:


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');
        });
      },
    );
  }
}

Weitere Informationen:


Um eine Liste zu erstellen, wird empfohlen, ListView.Builder zu verwenden .

Beispiel:


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');
        });
      },
    );
  }
}

Text


Frage:


Wie verwende ich benutzerdefinierte Schriftarten?

Antworten:


Die Schriftartdatei, die Sie nur in einen Ordner legen müssen (überlegen Sie sich einen Namen) und den Pfad dazu angeben pubspec.yaml.

Beispiel:


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'),
      ),
    ),
  );
}

Frage:


Wie gestalte ich Text-Widgets?

Antworten:


Parameter verwenden:

  • Farbe;
  • Dekoration;
  • Dekoration Farbe;
  • DekorationStyle;
  • Schriftfamilie;
  • Schriftgröße;
  • Schriftstil;
  • fontWeight;
  • Hash-Code;
  • Höhe;
  • erben;
  • Buchstaben-Abstand;
  • textBaseline;
  • wordSpacing.

Frage:


Was entspricht Platzhalter ?

Antworten:


Die noteText- Eigenschaft von InputDecoration .

Beispiel:


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

Frage:


Wie werden Validierungsfehler angezeigt?

Antworten:


Trotzdem mit InputDecoration und seinem Status.

Beispiel:


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);
  }
}

Flatter Plugins


Frage:


Wie greife ich auf GPS zu?

Antworten:


Verwenden des Geolocator- Plugins .

Frage:


Wie greife ich auf die Kamera zu?

Antworten:


Verwenden des image_picker- Plugins .

Frage:


Wie melde ich mich über Facebook an?

Antworten:


Verwenden des Plugins flutter_facebook_login .

Frage:


Wie benutzt man Firebase?

Antworten:


Firebase unterstützt Flutter-Plugins von Erstanbietern :

Plattformspezifischer Code


Frage:


Wie kann festgestellt werden, auf welcher Plattform der Code ausgeführt wird?

Antworten:


Verwenden der Feldklasse platformin Theme oder der Platform- Klasse .

Beispiel:


Feld 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 ';
}

Plattformklasse:
if (Platform.isIOS) {
  return 'iOS';
} else if (Platform.isAndroid) {
  return 'android';
} else if (Platform.isFuchsia) {
  return 'fuchsia';
} else {
  return 'not recognised ';
}

Frage:


Wie rufe ich nativen Plattformcode auf?

Antworten:


Über MethodChannel .

Weitere Informationen:


Weitere Details hier .

Debuggen


Frage:


Was sind die Tools zum Debuggen der Anwendung?

Antworten:


DevTools .

Frage:


Wie geht das hot reload?

Antworten:


Wenn die Anwendung über die IntelliJ IDE, Android Studio oder VSCode gestartet wurde, können ⌘s/ctrl-sSie das Symbol kombinieren oder darauf klicken hot reload. Wenn vom Terminal aus gestartet, geben Sie einen Buchstaben ein r.

Frage:


Wie greife ich in der Anwendung auf das Entwicklermenü zu?

Antworten:


Wenn der Start von der IDE aus erfolgte, verwenden Sie die IDE-Tools. Wenn von der Konsole aus, verwenden Sie h.

Weitere Informationen:


Vollständige Liste der Befehle:

HandlungTeam im TerminalFunktionen und Felder
Widget-HierarchiewdebugDumpApp ()
Baum renderntdebugDumpRenderTree ()
SchichtenL.debugDumpLayerTree ()
BarrierefreiheitS (Durchquerungsreihenfolge) oder U (inverse Treffer-Testreihenfolge)debugDumpSemantics ()
Widget-InspektorichWidgetsApp.showWidgetInspectorOverride
Konstruktionslinien anzeigenpdebugPaintSizeEnabled
Simulation verschiedener BetriebssystemeÖdefaultTargetPlatform
PerformanceP.WidgetsApp. showPerformanceOverlay
Screenshot flutter.pngs
Bewerbung schließenq

Lokaler Speicher


Frage:


Wie speichere ich key-valueDaten in der Anwendung?

Antworten:


Verwenden des Plugins shared_preferences .

Unterschiede:


In Xamarin.Forms wird verwendet Xam.Plugins.Settings.

Beispiel:


Verbindungsabhängigkeit:
dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^0.4.3

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

Frage:


Wie speichere ich komplexe Daten?

Antworten:


Mit Datenbank Plugins wie sqflite oder Bienenstock .

Hier sind vielleicht die Antworten auf die grundlegenden Fragen. Damit ist die Interpretationsreihe abgeschlossen. Ich hoffe, sie waren für alle Entwickler nützlich, die an diesem Framework interessiert sind. Vielleicht haben Sie sogar angefangen, über Flutter zu schreiben, und Sie in eine freundliche Community von Flutter-Entwicklern aufgenommen. Und ich werde über neue Artikel nachdenken, um die Community zu entwickeln und die Anwendungswelt zu einem besseren Ort zu machen. Mögen Ihre Formulare Xamarin nicht brechen!

All Articles