
Lassen Sie uns zunächst ein wenig darüber sprechen, was Flutter ist. Dies ist ein Framework zum Erstellen mobiler Anwendungen von Google. Es ist plattformübergreifend und ermöglicht es Ihnen, das erstellte Projekt für 3 Betriebssysteme zu kompilieren:
Darüber hinaus ist dies für das neueste Betriebssystem - Fuchsia - die einzige Möglichkeit, eine Anwendung zu erstellen.
Flutter wurde lange Zeit, seit 2015, nur in Alpha und Beta Versionen präsentiert. Die erste stabile Version wurde am 4. Dezember 2018 veröffentlicht.
Flutter wird von Google aktiv beworben, gewinnt allmählich an Popularität und wird höchstwahrscheinlich weiterhin andere derzeit verwendete plattformübergreifende Entwicklungstools (React Native, Xamarin) verdrängen, insbesondere wenn Fuchsia weit verbreitet ist. Da Google dieses Betriebssystem als Ersatz für Android positioniert, wird Flutter früher oder später die native Android-Entwicklung ersetzen. Perspektiven und aktive Entwicklung sind daher die Hauptvorteile von Flutter.
+ Perspektive und aktive Entwicklung
Mal sehen, wie es funktioniert.
In der Programmiersprache Dart wird eine mobile Anwendung mit einer Beschreibung der grafischen Oberfläche und der gesamten Arbeitslogik erstellt. Das Ergebnis der Arbeit wird der nativen Anwendung hinzugefügt, z. B. Bilder, Schriftarten und dergleichen (dieser Vorgang ist natürlich automatisiert).
Gleichzeitig wird im nativen Teil der Anwendung ein einzelner Bildschirm erstellt, auf dem die virtuelle Dart-Maschine geladen ist, auf der Flutter ausgeführt wird.
Beachten Sie, dass von hier aus einer der Minuspunkte von Flutter folgt:
- Das endgültige Installationspaket ist größer, da die virtuelle Dart-Maschine hinzugefügt wird.
Daher gibt es Flutter-Dateien und virtuelle Maschinen, die je nach Kompilierung hinzugefügt werden - iOS oder Android.
Die virtuelle Maschine verfügt über eine eigene Grafik-Engine. Sie zeichnet die Anwendungsoberfläche mit allen Übergängen zwischen Bildschirmen, Dialogen, Fragmenten usw. In dieser Hinsicht unterscheidet sich die Entwicklung unter Flutter erheblich von der Entwicklung mit Xamarin und React Native, die echte Android- und iOS-Komponenten verwenden. Bei ihnen ist es unmöglich, plattformspezifische Komponenten zu verwenden (wenn dies erforderlich ist, müssen Sie zwei Versionen der Benutzeroberfläche erstellen). Bei der Auswahl eines Designs mit Flutter reicht es aus, sich auf eine Plattform zu konzentrieren (z. B. Android). Wenn Sie ein Projekt für iOS erstellen, wird eine Standard-Android-Oberfläche angezeigt. Es wird ein wenig seltsam und unerwartet aussehen, aber ziemlich funktional (später kann die Oberfläche verbessert werden).
+ Eigene Grafik-Engine (keine separate Schnittstelle für Android und iOS erforderlich)
Nun zu den Eindrücken.
Beim Portieren mehrerer Anwendungen von Android nach Flutter haben wir einige Unterschiede festgestellt, die sowohl als Plus als auch als Minus betrachtet werden können.
Das erste, was auffällt, ist die Möglichkeit, Bildschirme zu erstellen, die sich erheblich von denen auf Android und iOS unterscheiden. In Android sind die Logik und die Schnittstelle getrennt: Die Logik wird durch Code festgelegt, und die Schnittstelle wird durch das Layout in XML festgelegt. Bei Flutter wird dies alles mithilfe von Code eingestellt. Obwohl hier ein spezieller Stil für die Schnittstelle verwendet wird, werden Schnittstellenelemente ineinander verschachtelt erstellt. Dies ist ein bisschen wie ein Layout, eine sehr ähnliche Art und Weise funktioniert in React Native. Es besteht jedoch keine Möglichkeit des direkten Zugriffs auf die Elemente. Um etwas auf dem Bildschirm zu ändern, müssen Sie entweder den gesamten Bildschirm aktualisieren oder spezielle Controller verwenden, die dem Widget während seiner Erstellung vorab hinzugefügt wurden.
- Die Schnittstelle wird mit Code erstellt, wodurch die Grenze zwischen Logik und Design viel dünner wird.
Andererseits erleichtert dieser Ansatz das Aufteilen von Bildschirmen in separate Komponenten. Tatsächlich kann jeder Block verschachtelter Schnittstellenelemente in nur wenigen Schritten in ein separates Widget verschoben werden. Dies ist viel einfacher als das Erstellen benutzerdefinierter Ansichten und Fragmente.
+ Die Schnittstelle ist einfach in separate Module zu unterteilen
Die letzten beiden Bemerkungen sind wahrscheinlich eine Prüfung wert. Zu diesem Zweck schreiben wir eine einfache Anwendung, die einige der Funktionen von Flutter demonstriert. Dies ist eine Anwendung mit einer Standardnavigationsleiste und einer Registerkartenleiste.
Lassen Sie uns drei Registerkarten erstellen:
1) Zuerst - mit Text und Schiebereglern, um die Größe und Farbe des Textes anzupassen
2) Fügen Sie dem zweiten ein Bild zum Herunterladen hinzu (mit Fortschrittsanzeige).
3) An dritter Stelle eine Beispielliste

Angenommen, wir haben die Anwendungsoberfläche zunächst nicht in separate Registerkarten aufgeteilt. In Flutter können Sie diesen Bildschirm ohne Verwendung von Fragmenten implementieren. Natürlich ist eine solche Partition immer noch wünschenswert, aber nehmen wir an, dass sie vergessen haben, dies zu tun, oder dass sich das Design geändert hat, wonach die Entwicklung durch Trägheit von einer Klasse fortgesetzt wurde.
Betrachten Sie nun den Quellcode, der dieses Layout implementiert:
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); }
Dieses Codefragment ist Standard für fast jede Flutter-Anwendung (es wird zusammen mit dem Projekt erstellt).
MyApp ist eine Klasse der Anwendung selbst, die die allgemeinen Parameter beim Erstellen von MaterialApp beschreibt: Anwendungsname, Schriftarten, Farben und Stile. Hier wird auch der Hauptbildschirm der Anwendung angezeigt (für uns ist dies MyHomePage).
Machen wir einen wichtigen Hinweis: In Flutter werden Widgets in zwei Typen unterteilt:
1) StatefulWidget
2) StatelessWidget
Zur Beschreibung von StatefulWidget sind zwei Klassen erforderlich: die Klasse des Widgets selbst und die Klasse seines Status (in dem die Hauptarbeit stattfinden wird).
StatelessWidget wird von einer Klasse mit festem Status beschrieben und kann nur durch erneutes Erstellen über das Haupt-Widget geändert werden. Daher ist für unsere Zwecke StatefulWidget erforderlich.
Betrachten Sie nun _MyHomePageState:
class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: <Widget>[
Zur Vereinfachung der Wahrnehmung sind eine Registerkarte mit Text rot, eine Registerkarte mit einem Bild in Grün, eine Listenregisterkarte in Blau und ein Navigationsmenü in Gelb markiert. Wie Sie sehen können, wird die Schnittstelle als eine Reihe von Widgets (und deren Arrays) beschrieben, die ineinander eingebettet sind:




Verwendete Funktionen:
void _onTapped(int index) { setState(() { _currentIndex = index; }); } void _setTextStyle( {double size = -1, double r = -1, double g = -1, double b = -1}) { setState(() { if (size > 0) { _size = size; } if (r > 0) { _r = r; } if (g > 0) { _g = g; } if (b > 0) { _b = b; } }); } }
Betrachten wir sie genauer:
onTapped - eine Funktion, die beim Wechseln einer Registerkarte im unteren Menü aufgerufen wird. Es ruft die spezielle setState-Funktion auf, mit der Sie das aktuelle Widget mit neuen Daten aktualisieren können (und wir haben die Variable _currentIndex aktualisiert).
Mal sehen, wo es gilt:
body: <Widget>[ ][_currentIndex]
Hier handelt es sich um ein Array, bei dem mit _currentIndex eine der Bildschirmlayoutoptionen ausgewählt und als eine der Registerkarten ersetzt wird.
Als nächstes kommt die _setTextStyle-Funktion. Es hat eine sehr ungewöhnliche Anzeige für C-ähnliche Sprachen.
void _setTextStyle({double size = -1, double r = -1, double g = -1,double b = -1})
Argumente werden nicht als Liste, sondern als Array übergeben. Dies ist eine der sehr interessanten Funktionen von Dart, mit der Sie Funktionen mit einer variablen Anzahl von Argumenten erstellen können, die viel feiner sind als in den meisten anderen Sprachen.
Da jedes Argument benannt ist, können wir sie in zufälliger Reihenfolge verwenden. Zum Beispiel:
_setTextStyle(size: 24, b: 255)
Teilen wir die Großbildklasse in Widgets auf. Es ist am besten, nach logischen Elementen aufzuschlüsseln. In unserem Fall handelt es sich um Registerkarten. Dank der Funktionen von Flutter reicht es aus, die für jede Registerkarte verantwortlichen Codefragmente zusammen mit der Logik in separate Klassen mit der Erstellungsmethode zu übertragen.
Erste Registerkarte:
class TextWidget extends StatefulWidget { @override _TextWidgetState createState() => _TextWidgetState(); } class _TextWidgetState extends State<TextWidget> { double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text("Example String", style: TextStyle( fontSize: _size, color: Color.fromRGBO(_r.toInt(), _g.toInt(), _b.toInt(), 1))), Container(constraints: BoxConstraints.expand(height: 32.0)), Slider( label: "${_size.toInt()} sp", value: _size, min: 10, max: 48, divisions: 38, activeColor: Colors.black, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(size: val)), Slider( label: _r.toInt().toString(), value: _r, min: 0, max: 255, divisions: 255, activeColor: Colors.red, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(r: val), ), Slider( label: _g.toInt().toString(), value: _g, min: 0, max: 255, divisions: 255, activeColor: Colors.green, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(g: val), ), Slider( label: _b.toInt().toString(), value: _b, min: 0, max: 255, divisions: 256, activeColor: Colors.blue, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(b: val), ), ], ); } }
Da das Widget aktualisiert werden muss (_setTextStyle-Methode), verwenden wir StatefulWidget.
Die nächsten beiden Registerkarten müssen nicht aktualisiert werden, daher verwenden wir StatelessWidget.
Zweite Registerkarte:
class ImageWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Stack( children: <Widget>[ Center(child: CircularProgressIndicator()), Center( child: FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: 'https://picsum.photos/250?image=9', ), ), ], ); } }
Dritte Registerkarte:
class ListWidget extends StatelessWidget { @override Widget build(BuildContext context) { return ListView.builder( itemCount: 25, itemBuilder: (BuildContext context, int index) { return Container( child: Text( 'entry $index', style: TextStyle(color: Colors.white), ), margin: EdgeInsets.all(16.0), padding: EdgeInsets.all(16.0), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.all( Radius.circular(16.0), ), ), ); }, ); } }
Statuscode des Hauptbildschirms geändert:
class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), actions: <Widget>[ IconButton(icon: Icon(Icons.navigate_next), onPressed: next) ], ), body: <Widget>[ TextWidget(), ImageWidget(), ListWidget(), ][_currentIndex], bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: _onTapped, items: [ BottomNavigationBarItem( icon: new Icon(Icons.text_format), title: new Text('Text'), ), BottomNavigationBarItem( icon: new Icon(Icons.image), title: new Text('Image'), ), BottomNavigationBarItem( icon: Icon(Icons.list), title: Text('ListView'), ) ], )); }
So können wir problemlos einen großen Bildschirm in einen kleinen Bildschirm und drei kleine Widgets aufteilen. Sie können feststellen, dass sich Flutter-Bildschirme konzeptionell nicht von Widgets unterscheiden (genauer gesagt, Widgets übernehmen die Funktionen Aktivität, Fragment und benutzerdefinierte Ansicht). Diese Funktion ist sehr praktisch, wenn die Anwendung eine Vollbildansicht eines Elements benötigt. Dazu können Sie unsere Widgets mit minimaler Verfeinerung verwenden.
Dennoch gibt es nur minimale Unterschiede zwischen einem Widget, das als Bildschirm verwendet wird, und einem regulären Widget. Das Stammelement für das Bildschirm-Widget sollte ein Scaffold-Objekt sein (ermöglicht das Hinzufügen von AppBar, BottomNavigationBar, FloatingActionButton, Drawer usw.).
Normale Widgets haben diese Einschränkung nicht, da sie mithilfe der Erstellungsmethode in den Hauptbildschirm eingebettet werden, in dem Scaffold bereits verfügbar ist.
Glücklicherweise wirkt sich das Hinzufügen von Scaffold zu einem regulären Widget nicht auf dessen Leistung aus.
Sie können auch SafeArea hinzufügen (um einen Einzug für die Statusleiste bereitzustellen). Die folgende einfache Umwandlung wird erhalten:
Von:
@override Widget build(BuildContext context) { return []; }
An:
@override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: [] ), ); }
Nun zurück zur Diskussion der Vor- und Nachteile von Flutter.
Flutter wurde kürzlich veröffentlicht, daher sind Fehler häufig genug. Dies macht sich insbesondere beim Aktualisieren von Flutter bemerkbar - einige Bibliotheken beginnen mit Fehlern zu arbeiten.
- Instabilität (erst kürzlich verlassene Beta)
Wenn Sie das neue Framework verwenden, stehen Ihnen natürlich viel weniger Bibliotheken zur Verfügung als bei der nativen Android / iOS-Entwicklung. Es gibt jedoch immer noch viele Bibliotheken für Flutter, und sie erscheinen weiterhin mit großer Geschwindigkeit. Beispielsweise wurden in der zweiten Hälfte des Jahres 2018 offenbar viele Bibliotheken hinzugefügt, um die erste stabile Version vorzubereiten, und die wichtigsten Bibliotheken (Google Analytics, Firebase, Maps usw.) existierten zuvor.
- Weniger Bibliotheken als für die native Entwicklung
+ Die wichtigsten Bibliotheken sind bereits vorhanden, es kommen ständig neue heraus
Es ist Zeit, Bilanz zu ziehen! Erinnern wir uns an alle Vor- und Nachteile und ordnen die Elemente von den wichtigsten Pluspunkten bis zu den wichtigsten Minuspunkten:
+ Plattformübergreifend
+ Perspektive und aktive Entwicklung
+ Die wichtigsten Bibliotheken sind bereits vorhanden, es kommen ständig neue heraus
+ Eigene Grafik-Engine
+ Die Schnittstelle ist einfach in separate Module zu unterteilen
- Das endgültige Installationspaket ist größer, da die virtuelle Dart-Maschine hinzugefügt wird
- Die Schnittstelle wird mit Code erstellt, wodurch die Grenze zwischen Logik und Design viel dünner wird
- Weniger Bibliotheken (und Informationen) als für die native Entwicklung
- Instabilität (erst kürzlich verlassene Beta)
Vielen Dank für Ihre Aufmerksamkeit!