Flattern - Kurzanleitung

Im Allgemeinen ist die Entwicklung einer mobilen Anwendung eine komplexe und herausfordernde Aufgabe. Für die Entwicklung einer mobilen Anwendung stehen viele Frameworks zur Verfügung. Android bietet ein natives Framework basierend auf der Java-Sprache und iOS bietet ein natives Framework basierend auf der Objective-C / Swift-Sprache.

Um jedoch eine Anwendung zu entwickeln, die beide Betriebssysteme unterstützt, müssen wir in zwei verschiedenen Sprachen mit zwei verschiedenen Frameworks codieren. Um diese Komplexität zu überwinden, gibt es mobile Frameworks, die beide Betriebssysteme unterstützen. Diese Frameworks reichen von einfachen HTML-basierten hybriden mobilen Anwendungsframeworks (die HTML für die Benutzeroberfläche und JavaScript für die Anwendungslogik verwenden) bis zu komplexen sprachspezifischen Frameworks (die das Konvertieren von Code in nativen Code erheblich erleichtern). Unabhängig von ihrer Einfachheit oder Komplexität weisen diese Frameworks immer viele Nachteile auf. Einer der Hauptnachteile ist ihre langsame Leistung.

In diesem Szenario bietet Flutter - ein einfaches und leistungsstarkes Framework, das auf der Dart-Sprache basiert - eine hohe Leistung, indem die Benutzeroberfläche direkt im Arbeitsbereich des Betriebssystems und nicht über ein natives Framework gerendert wird.

Flutter bietet auch viele gebrauchsfertige Widgets (UI), um eine moderne Anwendung zu erstellen. Diese Widgets sind für die mobile Umgebung optimiert und das Entwerfen der Anwendung mithilfe von Widgets ist so einfach wie das Entwerfen von HTML.

Um genau zu sein, ist die Flutter-Anwendung selbst ein Widget. Flatter-Widgets unterstützen auch Animationen und Gesten. Die Anwendungslogik basiert auf reaktiver Programmierung. Das Widget kann optional einen Status haben. Durch Ändern des Status des Widgets vergleicht Flutter automatisch (reaktive Programmierung) den Status des Widgets (alt und neu) und rendert das Widget nur mit den erforderlichen Änderungen, anstatt das gesamte Widget neu zu rendern.

Wir werden die gesamte Architektur in den kommenden Kapiteln diskutieren.

Eigenschaften von Flutter

Das Flutter Framework bietet Entwicklern die folgenden Funktionen:

  • Moderner und reaktiver Rahmen.

  • Verwendet die Programmiersprache Dart und ist sehr einfach zu erlernen.

  • Schnelle Entwicklung.

  • Schöne und flüssige Benutzeroberflächen.

  • Riesiger Widget-Katalog.

  • Führt dieselbe Benutzeroberfläche für mehrere Plattformen aus.

  • Hochleistungsanwendung.

Vorteile des Flatterns

Flutter wird mit schönen und anpassbaren Widgets für hohe Leistung und herausragende mobile Anwendungen geliefert. Es erfüllt alle kundenspezifischen Bedürfnisse und Anforderungen. Neben diesen bietet Flutter viele weitere Vorteile, wie unten erwähnt -

  • Dart verfügt über ein großes Repository an Softwarepaketen, mit denen Sie die Funktionen Ihrer Anwendung erweitern können.

  • Entwickler müssen für beide Anwendungen (sowohl Android- als auch iOS-Plattformen) nur eine einzige Codebasis schreiben. Flutter kann in Zukunft auch auf andere Plattformen ausgeweitet werden.

  • Das Flattern erfordert weniger Tests. Aufgrund der einzigen Codebasis ist es ausreichend, wenn wir automatisierte Tests einmal für beide Plattformen schreiben.

  • Die Einfachheit von Flutter macht es zu einem guten Kandidaten für eine schnelle Entwicklung. Seine Anpassungsfähigkeit und Erweiterbarkeit machen es noch leistungsfähiger.

  • Mit Flutter haben Entwickler die volle Kontrolle über die Widgets und deren Layout.

  • Flutter bietet großartige Entwicklertools mit erstaunlichem Hot-Reload.

Nachteile von Flattern

Trotz seiner vielen Vorteile weist das Flattern die folgenden Nachteile auf:

  • Da es in der Dart-Sprache codiert ist, muss ein Entwickler eine neue Sprache lernen (obwohl es leicht zu lernen ist).

  • Das moderne Framework versucht, Logik und Benutzeroberfläche so weit wie möglich zu trennen, aber in Flutter werden Benutzeroberfläche und Logik miteinander vermischt. Wir können dies durch intelligente Codierung und die Verwendung eines High-Level-Moduls zur Trennung von Benutzeroberfläche und Logik überwinden.

  • Flutter ist ein weiteres Framework zum Erstellen mobiler Anwendungen. Entwickler haben es schwer, die richtigen Entwicklungstools in einem dicht besiedelten Segment auszuwählen.

Dieses Kapitel führt Sie ausführlich durch die Installation von Flutter auf Ihrem lokalen Computer.

Installation unter Windows

In diesem Abschnitt erfahren Sie, wie Sie das Flutter SDK und seine Anforderungen in einem Windows-System installieren.

Step 1 - Zur URL gehen,https://flutter.dev/docs/get-started/install/windowsund laden Sie das neueste Flutter SDK herunter. Ab April 2019 ist die Version 1.2.1 und die Datei ist flutter_windows_v1.2.1-stable.zip.

Step 2 - Entpacken Sie das Zip-Archiv in einem Ordner, z. B. C: \ flutter \

Step 3 - Aktualisieren Sie den Systempfad, um das Flutter Bin-Verzeichnis einzuschließen.

Step 4 - Flutter bietet ein Werkzeug, Flatterarzt, um zu überprüfen, ob alle Anforderungen der Flatterentwicklung erfüllt sind.

flutter doctor

Step 5 - Wenn Sie den obigen Befehl ausführen, wird das System analysiert und der Bericht wie unten gezeigt angezeigt. -

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version
10.0.17134.706], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version
28.0.3)
[√] Android Studio (version 3.2)
[√] VS Code, 64-bit edition (version 1.29.1)
[!] Connected device
! No devices available
! Doctor found issues in 1 category.

Der Bericht besagt, dass alle Entwicklungstools verfügbar sind, das Gerät jedoch nicht angeschlossen ist. Wir können dies beheben, indem wir ein Android-Gerät über USB anschließen oder einen Android-Emulator starten.

Step 6 - Installieren Sie das neueste Android SDK, wenn dies vom Flatterarzt gemeldet wird

Step 7 - Installieren Sie das neueste Android Studio, wenn dies vom Flatterarzt gemeldet wird

Step 8 - Starten Sie einen Android-Emulator oder verbinden Sie ein echtes Android-Gerät mit dem System.

Step 9- Installieren Sie das Flutter and Dart Plugin für Android Studio. Es bietet eine Startvorlage zum Erstellen einer neuen Flutter-Anwendung, eine Option zum Ausführen und Debuggen der Flutter-Anwendung im Android Studio selbst usw.

  • Öffnen Sie Android Studio.

  • Klicken Sie auf Datei → Einstellungen → Plugins.

  • Wählen Sie das Flutter-Plugin und klicken Sie auf Installieren.

  • Klicken Sie auf Ja, wenn Sie aufgefordert werden, das Dart-Plugin zu installieren.

  • Starten Sie Android Studio neu.

Installation unter MacOS

Um Flutter unter MacOS zu installieren, müssen Sie die folgenden Schritte ausführen:

Step 1 - Zur URL gehen,https://flutter.dev/docs/get-started/install/macosund laden Sie das neueste Flutter SDK herunter. Ab April 2019 ist die Version 1.2.1 und die Datei ist flutter_macos_v1.2.1-stable.zip.

Step 2 - Entpacken Sie das Zip-Archiv in einem Ordner, z. B. / path / to / flutter

Step 3 - Aktualisieren Sie den Systempfad so, dass er das Verzeichnis flutter bin enthält (in der Datei ~ / .bashrc).

> export PATH = "$PATH:/path/to/flutter/bin"

Step 4 - Aktivieren Sie den aktualisierten Pfad in der aktuellen Sitzung mit dem folgenden Befehl und überprüfen Sie ihn dann ebenfalls.

source ~/.bashrc
source $HOME/.bash_profile
echo $PATH

Flutter bietet ein Werkzeug, Flatterarzt, um zu überprüfen, ob alle Anforderungen der Flatterentwicklung erfüllt sind. Es ähnelt dem Windows-Gegenstück.

Step 5 - Installieren Sie den neuesten XCode, wenn dies vom Flatterarzt gemeldet wird

Step 6 - Installieren Sie das neueste Android SDK, wenn dies vom Flatterarzt gemeldet wird

Step 7 - Installieren Sie das neueste Android Studio, wenn dies vom Flatterarzt gemeldet wird

Step 8 - Starten Sie einen Android-Emulator oder verbinden Sie ein echtes Android-Gerät mit dem System, um eine Android-Anwendung zu entwickeln.

Step 9 - Öffnen Sie den iOS-Simulator oder verbinden Sie ein echtes iPhone-Gerät mit dem System, um eine iOS-Anwendung zu entwickeln.

Step 10- Installieren Sie das Flutter and Dart Plugin für Android Studio. Es bietet die Startvorlage zum Erstellen einer neuen Flutter-Anwendung, die Option zum Ausführen und Debuggen der Flutter-Anwendung im Android Studio selbst usw.

  • Öffnen Sie Android Studio

  • Klicken Preferences → Plugins

  • Wählen Sie das Flutter-Plugin und klicken Sie auf Installieren

  • Klicken Sie auf Ja, wenn Sie aufgefordert werden, das Dart-Plugin zu installieren.

  • Starten Sie Android Studio neu.

In diesem Kapitel erstellen wir eine einfache Flatteranwendung , um die Grundlagen zum Erstellen einer Flatteranwendung in Android Studio zu verstehen.

Step 1 - Öffnen Sie Android Studio

Step 2- Flatterprojekt erstellen. Klicken Sie dazu aufFile → New → New Flutter Project

Step 3- Wählen Sie Flatteranwendung. Wählen Sie dazuFlutter Application und klicken Sie auf Next.

Step 4 - Konfigurieren Sie die Anwendung wie folgt und klicken Sie auf Next.

  • Projektname: hello_app

  • Flatter SDK-Pfad: <path_to_flutter_sdk>

  • Projektstandort: <path_to_project_folder>

  • Beschreibung: Flutter based hello world application

Step 5 - Projekt konfigurieren.

Legen Sie die Unternehmensdomäne als fest flutterapp.tutorialspoint.com und klicken Sie auf Finish.

Step 6 - Geben Sie die Unternehmensdomäne ein.

Android Studio erstellt eine voll funktionsfähige Flatteranwendung mit minimaler Funktionalität. Lassen Sie uns die Struktur der Anwendung überprüfen und dann den Code ändern, um unsere Aufgabe zu erledigen.

Die Struktur der Anwendung und ihr Zweck ist wie folgt:

Hier werden verschiedene Komponenten der Struktur der Anwendung erläutert -

  • android - Automatisch generierter Quellcode zum Erstellen einer Android-Anwendung

  • ios - Automatisch generierter Quellcode zum Erstellen einer iOS-Anwendung

  • lib - Hauptordner mit Dart-Code, der mit dem Flatter-Framework geschrieben wurde

  • ib/main.dart - Einstiegspunkt der Flutter-Anwendung

  • test - Ordner mit Dart-Code zum Testen der Flatteranwendung

  • test/widget_test.dart - Beispielcode

  • .gitignore - Git-Versionskontrolldatei

  • .metadata - automatisch von den Flatterwerkzeugen erzeugt

  • .packages - automatisch generiert, um die Flatterpakete zu verfolgen

  • .iml - Projektdatei, die von Android Studio verwendet wird

  • pubspec.yaml - Verwendet von Pub, Flutter Paketmanager

  • pubspec.lock - Automatisch generiert vom Flutter-Paketmanager, Pub

  • README.md - Projektbeschreibungsdatei im Markdown-Format

Step 7- Ersetzen Sie den Dartcode in der Datei lib / main.dart durch den folgenden Code. -

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application',
         theme: ThemeData(
            primarySwatch: Colors.blue,
         ),
         home: MyHomePage(title: 'Home page'),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;

   @override
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title),
         ),
         body: Center(
            child:
            Text(
               'Hello World',
            )
         ),
      );
   }
}

Lassen Sie uns den Dartcode Zeile für Zeile verstehen.

  • Line 1- Importiert das Flatterpaket, Material . Das Material ist ein Flatterpaket zum Erstellen einer Benutzeroberfläche gemäß den von Android festgelegten Materialdesign-Richtlinien.

  • Line 3- Dies ist der Einstiegspunkt der Flutter-Anwendung. Anrufe runapp Funktion und ein Objekt übergeben MeineAnw Klasse. Der Zweck der runApp- Funktion besteht darin, das angegebene Widget an den Bildschirm anzuhängen.

  • Line 5-17- Widget wird verwendet, um eine Benutzeroberfläche im Flatter-Framework zu erstellen. StatelessWidget ist ein Widget, das keinen Status des Widgets beibehält. MyApp erweitert StatelessWidget und überschreibt seine Erstellungsmethode . Der Zweck der Erstellungsmethode besteht darin, einen Teil der Benutzeroberfläche der Anwendung zu erstellen. Hier build - Methode verwendet MaterialApp , ein Widget der Stammebene UI der Anwendung zu erstellen. Es hat drei Eigenschaften - Titel, Thema und Heimat .

    • Titel ist der Titel der Anwendung

    • Thema ist das Thema des Widgets. Hier legen wir Blau als Gesamtfarbe der Anwendung fest, indem wir die ThemeData- Klasse und ihre Eigenschaft primarySwatch verwenden .

    • home ist die innere Benutzeroberfläche der Anwendung, für die wir ein weiteres Widget festgelegt haben. MyHomePage

  • Line 19 - 38- MyHomePage ist mit MyApp identisch , gibt jedoch das Scaffold Widget zurück. Scaffold ist ein Widget der obersten Ebene neben dem MaterialApp- Widget, mit dem ein UI-konformes Materialdesign erstellt wird. Es hat zwei wichtige Eigenschaften: appBar , um den Header der Anwendung anzuzeigen , und body, um den tatsächlichen Inhalt der Anwendung anzuzeigen . AppBar ist ein weiteres Widget zum Rendern des Headers der Anwendung, das wir in der Eigenschaft appBar verwendet haben . In der Eigenschaft body haben wir das Widget " Center" verwendet , mit dem das untergeordnete Widget zentriert wird. Text ist das letzte und innerste Widget, mit dem der Text angezeigt wird. Er wird in der Mitte des Bildschirms angezeigt.

Step 8 - Führen Sie nun die Anwendung aus mit: Run → Run main.dart

Step 9 - Schließlich ist die Ausgabe der Anwendung wie folgt:

Lassen Sie uns in diesem Kapitel die Architektur des Flutter-Frameworks diskutieren.

Widgets

Das Kernkonzept des Flutter-Frameworks ist In Flutter, Everything is a widget. Widgets sind im Wesentlichen Benutzeroberflächenkomponenten, mit denen die Benutzeroberfläche der Anwendung erstellt wird.

In Flutter ist die Anwendung selbst ein Widget. Die Anwendung ist das Widget der obersten Ebene, und die Benutzeroberfläche wird mit einem oder mehreren untergeordneten Widgets (Widgets) erstellt, die wiederum mit den untergeordneten Widgets erstellt werden. Diesecomposability Mit dieser Funktion können wir eine Benutzeroberfläche beliebiger Komplexität erstellen.

Die Widget-Hierarchie der Hello World-Anwendung (im vorherigen Kapitel erstellt) entspricht beispielsweise der folgenden Abbildung:

Hier sind folgende Punkte bemerkenswert -

  • MyApp ist das vom Benutzer erstellte Widget und wird mit dem nativen Flutter-Widget MaterialApp erstellt .

  • MaterialApp verfügt über eine Home-Eigenschaft, mit der die Benutzeroberfläche der Homepage angegeben wird . Hierbei handelt es sich wiederum um ein vom Benutzer erstelltes Widget, MyHomePage .

  • MyHomePage wird mit einem anderen nativen Flatter-Widget, Scaffold, erstellt

  • Das Gerüst hat zwei Eigenschaften - body und appBar

  • body wird verwendet, um die Hauptbenutzeroberfläche anzugeben, und appBar wird verwendet, um die Header-Benutzeroberfläche anzugeben

  • Die Header-Benutzeroberfläche wird mit dem nativen Flatter-Widget erstellt, AppBar und die Body-Benutzeroberfläche mit dem Center- Widget.

  • Das Center- Widget verfügt über die Eigenschaft Child , die auf den tatsächlichen Inhalt verweist und mithilfe des Text- Widgets erstellt wird

Gesten

Flatter-Widgets unterstützen die Interaktion über ein spezielles Widget, GestureDetector . GestureDetector ist ein unsichtbares Widget, mit dem Benutzerinteraktionen wie Tippen, Ziehen usw. des untergeordneten Widgets erfasst werden können. Viele native Flutter-Widgets unterstützen die Interaktion mithilfe von GestureDetector . Wir können interaktive Funktionen auch in das vorhandene Widget integrieren, indem wir sie mit dem GestureDetector- Widget erstellen . Wir werden die Gesten in den kommenden Kapiteln separat lernen.

Staatskonzept

Flutter - Widgets unterstützen staatliche Wartung durch ein spezielles Widget bereitstellt, StatefulWidget . Das Widget muss vom StatefulWidget- Widget abgeleitet werden, um die Statusverwaltung zu unterstützen, und alle anderen Widgets sollten vom StatefulWidget abgeleitet werden . Flattern Widgets sindreactivein native. Dies ist ähnlich wie bei reactjs und StatefulWidget wird automatisch neu gerendert, wenn sein interner Status geändert wird. Das erneute Rendern wird optimiert, indem der Unterschied zwischen der alten und der neuen Widget-Benutzeroberfläche ermittelt und nur die erforderlichen Änderungen gerendert werden

Schichten

Das wichtigste Konzept des Flutter-Frameworks besteht darin, dass das Framework hinsichtlich seiner Komplexität in mehrere Kategorien eingeteilt und in Schichten mit abnehmender Komplexität klar angeordnet ist. Eine Ebene wird mit ihrer unmittelbaren Ebene der nächsten Ebene erstellt. Die oberste Ebene ist ein Widget, das für Android und iOS spezifisch ist . Die nächste Ebene enthält alle nativen Widgets. Die nächste Ebene ist die Rendering- Ebene, eine Renderer-Komponente auf niedriger Ebene, die alles in der Flatter-App rendert. Ebenen gehen auf plattformspezifischen Kerncode zurück

Die allgemeine Übersicht über eine Ebene in Flutter ist in der folgenden Abbildung dargestellt.

Die folgenden Punkte fassen die Architektur von Flutter zusammen -

  • In Flutter ist alles ein Widget und ein komplexes Widget besteht aus bereits vorhandenen Widgets.

  • Interaktive Funktionen können bei Bedarf mithilfe des GestureDetector- Widgets integriert werden.

  • Der Status eines Widgets kann bei Bedarf mithilfe des StatefulWidget- Widgets beibehalten werden .

  • Flutter bietet ein mehrschichtiges Design, sodass jede Ebene je nach Komplexität der Aufgabe programmiert werden kann.

Wir werden all diese Konzepte in den kommenden Kapiteln ausführlich diskutieren.

Dart ist eine Open-Source-Programmiersprache für allgemeine Zwecke. Es wurde ursprünglich von Google entwickelt. Dart ist eine objektorientierte Sprache mit C-Syntax. Es unterstützt Programmierkonzepte wie Schnittstellen und Klassen, im Gegensatz zu anderen Programmiersprachen unterstützt Dart keine Arrays. Dart-Sammlungen können verwendet werden, um Datenstrukturen wie Arrays, Generika und optionale Typisierung zu replizieren.

Der folgende Code zeigt ein einfaches Dart-Programm -

void main() {
   print("Dart language is easy to learn");
}

Variablen und Datentypen

Die Variable wird als Speicherort bezeichnet, und Datentypen beziehen sich einfach auf den Typ und die Größe der Daten, die Variablen und Funktionen zugeordnet sind.

Dart verwendet das Schlüsselwort var , um die Variable zu deklarieren. Die Syntax von var ist unten definiert:

var name = 'Dart';

Das Schlüsselwort final und const wird verwendet, um Konstanten zu deklarieren. Sie sind wie folgt definiert:

void main() {
   final a = 12;
   const pi = 3.14;
   print(a);
   print(pi);
}

Die Dartsprache unterstützt die folgenden Datentypen:

  • Numbers - Es wird verwendet, um numerische Literale darzustellen - Integer und Double.

  • Strings- Es repräsentiert eine Folge von Zeichen. Zeichenfolgenwerte werden entweder in einfachen oder doppelten Anführungszeichen angegeben.

  • Booleans- Dart verwendet das Schlüsselwort bool , um boolesche Werte darzustellen - true und false.

  • Lists and Maps- Es wird verwendet, um eine Sammlung von Objekten darzustellen. Eine einfache Liste kann wie folgt definiert werden :.

void main() {
   var list = [1,2,3,4,5];
   print(list);
}

Die oben gezeigte Liste erzeugt eine [1,2,3,4,5] Liste.

Karte kann wie hier gezeigt definiert werden -

void main() {
   var mapping = {'id': 1,'name':'Dart'};
   print(mapping);
}
  • Dynamic- Wenn der Variablentyp nicht definiert ist, ist sein Standardtyp dynamisch. Das folgende Beispiel zeigt die dynamische Typvariable -

void main() {
   dynamic name = "Dart";
   print(name);
}

Entscheidungsfindung und Schleifen

Ein Entscheidungsblock wertet eine Bedingung aus, bevor die Anweisungen ausgeführt werden. Dart unterstützt If-, If..else- und switch-Anweisungen.

Schleifen werden verwendet, um einen Codeblock zu wiederholen, bis eine bestimmte Bedingung erfüllt ist. Dart unterstützt for, for..in, while und do..while-Schleifen.

Lassen Sie uns ein einfaches Beispiel für die Verwendung von Steueranweisungen und Schleifen verstehen -

void main() {
   for( var i = 1 ; i <= 10; i++ ) {
      if(i%2==0) {
         print(i);
      }
   }
}

Der obige Code gibt die geraden Zahlen von 1 bis 10 aus.

Funktionen

Eine Funktion ist eine Gruppe von Anweisungen, die zusammen eine bestimmte Aufgabe ausführen. Lassen Sie uns eine einfache Funktion in Dart untersuchen, wie hier gezeigt -

void main() {
   add(3,4);
}
void add(int a,int b) {
   int c;
   c = a+b;
   print(c);
}

Die obige Funktion addiert zwei Werte und erzeugt 7 als Ausgabe.

Objekt orientierte Programmierung

Dart ist eine objektorientierte Sprache. Es unterstützt objektorientierte Programmierfunktionen wie Klassen, Schnittstellen usw.

Eine Klasse ist eine Blaupause zum Erstellen von Objekten. Eine Klassendefinition enthält Folgendes:

  • Fields
  • Getter und Setter
  • Constructors
  • Functions

Lassen Sie uns nun eine einfache Klasse mit den obigen Definitionen erstellen -

class Employee {
   String name;
   
   //getter method
   String get emp_name {
      return name;
   }
   //setter method
   void set emp_name(String name) {
      this.name = name;
   }
   //function definition
   void result() {
      print(name);
   }
}
void main() {
   //object creation
   Employee emp = new Employee();
   emp.name = "employee1";
   emp.result(); //function call
}

Wie wir im vorherigen Kapitel erfahren haben, sind Widgets alles im Flutter-Framework. In früheren Kapiteln haben wir bereits gelernt, wie neue Widgets erstellt werden.

Lassen Sie uns in diesem Kapitel das eigentliche Konzept zum Erstellen der Widgets und die verschiedenen Arten von Widgets verstehen, die im Flutter- Framework verfügbar sind .

Lassen Sie uns das MyHomePage- Widget der Hello World- Anwendung überprüfen . Der Code für diesen Zweck lautet wie folgt:

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar(title: Text(this.title), ), 
         body: Center(child: Text( 'Hello World',)),
      );
   }
}

Hier haben wir ein neues Widget erstellt, indem wir StatelessWidget erweitert haben .

Beachten Sie, dass die StatelessWidget nur eine einzige Methode erfordert build in seiner abgeleiteten Klasse implementiert werden. Die Erstellungsmethode ruft die zum Erstellen der Widgets erforderliche Kontextumgebung über den BuildContext- Parameter ab und gibt das erstellte Widget zurück.

Im Code haben wir title als eines der Konstruktorargumente und Key als weiteres Argument verwendet. Der Titel wird verwendet, um den Titel anzuzeigen, und der Schlüssel wird verwendet, um das Widget in der Build-Umgebung zu identifizieren.

Hier wird die Build ruft Methode , um die Build - Methode von Scaffold , die wiederum ruft die Build - Methode von AppBar und Zentrum zu bauen seine Benutzeroberfläche.

Schließlich ruft die Center- Erstellungsmethode die Texterstellungsmethode auf .

Zum besseren Verständnis ist die visuelle Darstellung derselben unten angegeben -

Widget-Build-Visualisierung

In Flutter können Widgets basierend auf ihren Funktionen in mehrere Kategorien eingeteilt werden, wie unten aufgeführt.

  • Plattformspezifische Widgets
  • Layout-Widgets
  • Widgets für die Statuswartung
  • Plattformunabhängige / grundlegende Widgets

Lassen Sie uns jetzt jeden von ihnen im Detail besprechen.

Plattformspezifische Widgets

Flutter verfügt über spezifische Widgets für eine bestimmte Plattform - Android oder iOS.

Android-spezifische Widgets werden gemäß der Material Design-Richtlinie von Android OS entwickelt. Android-spezifische Widgets werden als Material-Widgets bezeichnet .

iOS-spezifische Widgets wurden gemäß den Richtlinien für Benutzeroberflächen von Apple entwickelt und als Cupertino- Widgets bezeichnet.

Einige der am häufigsten verwendeten Material-Widgets sind:

  • Scaffold
  • AppBar
  • BottomNavigationBar
  • TabBar
  • TabBarView
  • ListTile
  • RaisedButton
  • FloatingActionButton
  • FlatButton
  • IconButton
  • DropdownButton
  • PopupMenuButton
  • ButtonBar
  • TextField
  • Checkbox
  • Radio
  • Switch
  • Slider
  • Datums- und Zeitauswahl
  • SimpleDialog
  • AlertDialog

Einige der am häufigsten verwendeten Cupertino- Widgets sind:

  • CupertinoButton
  • CupertinoPicker
  • CupertinoDatePicker
  • CupertinoTimerPicker
  • CupertinoNavigationBar
  • CupertinoTabBar
  • CupertinoTabScaffold
  • CupertinoTabView
  • CupertinoTextField
  • CupertinoDialog
  • CupertinoDialogAction
  • CupertinoFullscreenDialogTransition
  • CupertinoPageScaffold
  • CupertinoPageTransition
  • CupertinoActionSheet
  • CupertinoActivityIndicator
  • CupertinoAlertDialog
  • CupertinoPopupSurface
  • CupertinoSlider

Layout-Widgets

In Flutter kann ein Widget erstellt werden, indem ein oder mehrere Widgets erstellt werden. Um mehrere Widgets zu einem einzigen Widget zusammenzusetzen, bietet Flutter eine große Anzahl von Widgets mit Layoutfunktion. Beispielsweise kann das untergeordnete Widget mithilfe des Center- Widgets zentriert werden .

Einige der beliebtesten Layout-Widgets sind wie folgt:

  • Container- Eine rechteckige Box, die mit BoxDecoration- Widgets mit Hintergrund, Rand und Schatten dekoriert wurde .

  • Center - Zentrieren Sie das untergeordnete Widget.

  • Row - Ordnen Sie die Kinder in horizontaler Richtung an.

  • Column - Ordnen Sie die Kinder in vertikaler Richtung an.

  • Stack - Übereinander anordnen.

Wir werden die Layout-Widgets im kommenden Kapitel Einführung in Layout-Widgets im Detail überprüfen .

Widgets für die Statuswartung

In Flutter werden alle Widgets entweder von StatelessWidget oder StatefulWidget abgeleitet .

Von StatelessWidget abgeleitetes Widget enthält keine Statusinformationen, kann jedoch von StatefulWidget abgeleitetes Widget enthalten . Die Dynamik der Anwendung beruht auf dem interaktiven Verhalten der Widgets und den Statusänderungen während der Interaktion. Wenn Sie beispielsweise auf eine Zählertaste tippen, wird der interne Status des Zählers um eins erhöht / verringert, und durch die reaktive Natur des Flutter- Widgets wird das Widget mithilfe neuer Statusinformationen automatisch neu gerendert.

Wir werden das Konzept der StatefulWidget- Widgets im kommenden Kapitel zur Staatsverwaltung ausführlich kennenlernen .

Plattformunabhängige / grundlegende Widgets

Flutter bietet eine große Anzahl grundlegender Widgets, um auf plattformunabhängige Weise sowohl einfache als auch komplexe Benutzeroberflächen zu erstellen. Sehen wir uns einige der grundlegenden Widgets in diesem Kapitel an.

Text

Das Text- Widget wird verwendet, um ein Stück Zeichenfolge anzuzeigen. Der Stil des Strings kann durch die Verwendung eingestellt werden Stil Eigenschaft und Textstyle - Klasse. Der Beispielcode für diesen Zweck lautet wie folgt:

Text('Hello World!', style: TextStyle(fontWeight: FontWeight.bold))

Das Text- Widget verfügt über einen speziellen Konstruktor, Text.rich , der das untergeordnete Element vom Typ TextSpan akzeptiert , um die Zeichenfolge mit einem anderen Stil anzugeben. Das TextSpan- Widget ist rekursiver Natur und akzeptiert TextSpan als untergeordnete Elemente . Der Beispielcode für diesen Zweck lautet wie folgt:

Text.rich( 
   TextSpan( 
      children: <TextSpan>[ 
         TextSpan(text: "Hello ", style:  
         TextStyle(fontStyle: FontStyle.italic)),  
         TextSpan(text: "World", style: 
         TextStyle(fontWeight: FontWeight.bold)),  
      ], 
   ), 
)

Die wichtigsten Eigenschaften des Text- Widgets sind:

  • maxLines, int - Maximale Anzahl der anzuzeigenden Zeilen

  • overflow, TextOverFlow- Geben Sie an, wie der visuelle Überlauf mithilfe der TextOverFlow- Klasse behandelt wird

  • style, TextStyle- Geben Sie den Stil der Zeichenfolge mithilfe der TextStyle- Klasse an

  • textAlign, TextAlign- Ausrichtung des Textes wie rechts, links, ausrichten usw. mithilfe der TextAlign- Klasse

  • textDirection, TextDirection - Richtung des Textflusses, entweder von links nach rechts oder von rechts nach links

Image

Das Bild- Widget wird verwendet, um ein Bild in der Anwendung anzuzeigen. Das Bild- Widget bietet verschiedene Konstruktoren zum Laden von Bildern aus mehreren Quellen. Diese lauten wie folgt:

  • Image- Generischer Image Loader mit ImageProvider

  • Image.asset - Laden Sie das Bild aus den Assets des Flatterprojekts

  • Image.file - Laden Sie das Image aus dem Systemordner

  • Image.memory - Bild aus dem Speicher laden

  • Image.Network - Laden Sie das Bild aus dem Netzwerk

Die einfachste Möglichkeit, ein Bild in Flutter zu laden und anzuzeigen, besteht darin, das Bild als Assets der Anwendung einzuschließen und es bei Bedarf in das Widget zu laden.

  • Erstellen Sie einen Ordner und Assets im Projektordner und platzieren Sie die erforderlichen Bilder.

  • Geben Sie die Assets in der Datei pubspec.yaml wie unten gezeigt an -

flutter: 
   assets: 
      - assets/smiley.png
  • Laden Sie nun das Bild und zeigen Sie es in der Anwendung an.

Image.asset('assets/smiley.png')
  • Der vollständige Quellcode des MyHomePage- Widgets der Hello World-Anwendung und das Ergebnis sind wie folgt :.

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

   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( title: Text(this.title), ), 
         body: Center( child: Image.asset("assets/smiley.png")),
      ); 
   }
}

Das geladene Bild ist wie unten gezeigt -

Die wichtigsten Eigenschaften des Bild- Widgets sind:

  • image, ImageProvider - Tatsächlich zu ladendes Bild

  • width, double - Breite des Bildes

  • height, double - Höhe des Bildes

  • alignment, AlignmentGeometry - So richten Sie das Bild innerhalb seiner Grenzen aus

Icon

Das Symbol- Widget wird verwendet, um eine Glyphe aus einer in der IconData- Klasse beschriebenen Schriftart anzuzeigen . Der Code zum Laden eines einfachen E-Mail-Symbols lautet wie folgt:

Icon(Icons.email)

Der vollständige Quellcode zum Anwenden in der Hallo-Welt-Anwendung lautet wie folgt:

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

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center( child: Icon(Icons.email)),
      );
   }
}

Das geladene Symbol ist wie unten gezeigt -

Da das Kernkonzept von Flutter ist Alles ist Widget , Flutter verfügt über eine Layout - Funktionalität Benutzeroberfläche in die Widgets selbst. Flutter bietet eine Vielzahl von speziell entwickelten Widgets wie Container, Center, Align usw., nur um die Benutzeroberfläche zu gestalten. Widgets, die durch Erstellen anderer Widgets erstellt werden, verwenden normalerweise Layout-Widgets. Lernen Sie das Flutter- Layout-Konzept in diesem Kapitel kennen.

Art der Layout-Widgets

Layout-Widgets können basierend auf ihrem untergeordneten Element in zwei verschiedene Kategorien eingeteilt werden:

  • Widget, das ein einzelnes Kind unterstützt
  • Widget, das mehrere Kinder unterstützt

Lassen Sie uns in den nächsten Abschnitten sowohl die Art der Widgets als auch deren Funktionalität kennenlernen.

Widgets für einzelne Kinder

In dieser Kategorie haben Widgets nur ein Widget als untergeordnetes Element, und jedes Widget verfügt über eine spezielle Layoutfunktion.

Zum Beispiel Zentrum Widget zentriert es nur Kind - Widget mit Bezug auf ihre Mutter Widget und Container - Widget vollständige Flexibilität bietet ihm zu platzieren Kind zu einem bestimmten Ort im Innern andere Option wie Polsterung, Dekoration usw. verwendet wird ,

Widgets für einzelne Kinder sind großartige Optionen, um hochwertige Widgets mit einzelnen Funktionen wie Schaltflächen, Beschriftungen usw. zu erstellen.

Der Code zum Erstellen einer einfachen Schaltfläche mit dem Container- Widget lautet wie folgt:

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

Hier haben wir zwei Widgets verwendet - ein Container- Widget und ein Text- Widget. Das Ergebnis des Widgets ist eine benutzerdefinierte Schaltfläche (siehe unten).

Lassen wir uns von zur Verfügung gestellt einige der wichtigsten einzelne Kind Layout - Widgets überprüfen Flutter -

  • Padding- Wird verwendet, um das untergeordnete Widget anhand der angegebenen Polsterung anzuordnen. Hier kann das Auffüllen durch die EdgeInsets- Klasse bereitgestellt werden .

  • Align- Richten Sie das untergeordnete Widget mithilfe des Werts der Ausrichtungseigenschaft in sich selbst aus . Der Wert für die Ausrichtungseigenschaft kann von der FractionalOffset- Klasse bereitgestellt werden . Die FractionalOffset- Klasse gibt die Offsets als Abstand von oben links an.

Einige der möglichen Werte für Offsets sind wie folgt:

  • FractionalOffset (1.0, 0.0) steht oben rechts.

  • FractionalOffset (0.0, 1.0) steht unten links.

Ein Beispielcode für Offsets ist unten dargestellt -

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox - Es skaliert das untergeordnete Widget und positioniert es dann entsprechend der angegebenen Anpassung.

  • AspectRatio - Es wird versucht, die Größe des untergeordneten Widgets auf das angegebene Seitenverhältnis zu ändern

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

Unsere Hallo-Welt-Anwendung verwendet materialbasierte Layout-Widgets, um die Homepage zu gestalten. Lassen Sie uns unsere Hello World-Anwendung so ändern, dass die Homepage mithilfe der unten angegebenen grundlegenden Layout-Widgets erstellt wird.

  • Container - Allgemeines, einzelnes untergeordnetes, boxbasiertes Container-Widget mit Ausrichtung, Auffüllung, Rand und Rand sowie umfangreichen Styling-Funktionen.

  • Center - Einfaches, einzelnes untergeordnetes Container-Widget, das das untergeordnete Widget zentriert.

Der geänderte Code des MyHomePage- und MyApp- Widgets lautet wie folgt:

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

Hier,

  • Das Container- Widget ist das Widget der obersten Ebene oder des Stamm-Widgets. Der Container wird mithilfe der Dekoration und der Polsterungseigenschaft konfiguriert, um seinen Inhalt zu gestalten.

  • BoxDecoration verfügt über viele Eigenschaften wie Farbe, Rahmen usw., um das Container- Widget zu dekorieren. Hier wird Farbe verwendet, um die Farbe des Containers festzulegen .

  • Das Auffüllen des Container- Widgets wird mithilfe der dgeInsets- Klasse festgelegt, die die Option zum Angeben des Auffüllwerts bietet.

  • Center ist das untergeordnete Widget des Container- Widgets. Auch hier ist Text das untergeordnete Element des Center- Widgets. Text wird verwendet, um die Nachricht anzuzeigen, und Center wird verwendet, um die Textnachricht in Bezug auf das übergeordnete Widget Container zu zentrieren .

Das Endergebnis des oben angegebenen Codes ist ein Layoutbeispiel wie unten gezeigt -

Mehrere untergeordnete Widgets

In dieser Kategorie verfügt ein bestimmtes Widget über mehr als ein untergeordnetes Widget, und das Layout jedes Widgets ist eindeutig.

Das Zeilen- Widget ermöglicht beispielsweise das Layout der untergeordneten Elemente in horizontaler Richtung, während das Spalten- Widget das Layout der untergeordneten Elemente in vertikaler Richtung ermöglicht. Durch das Erstellen von Zeilen und Spalten kann ein Widget mit beliebiger Komplexität erstellt werden.

Lassen Sie uns einige der häufig verwendeten Widgets in diesem Abschnitt kennenlernen.

  • Row - Ermöglicht die horizontale Anordnung der Kinder.

  • Column - Ermöglicht die vertikale Anordnung der Kinder.

  • ListView - Ermöglicht das Anordnen der untergeordneten Elemente als Liste.

  • GridView - Ermöglicht die Anordnung seiner Kinder als Galerie.

  • Expanded - Wird verwendet, um die untergeordneten Elemente des Zeilen- und Spalten-Widgets so zu gestalten, dass sie den maximal möglichen Bereich belegen.

  • Table - Tabellenbasiertes Widget.

  • Flow - Flow-basiertes Widget.

  • Stack - Stapelbasiertes Widget.

Erweiterte Layout-Anwendung

In diesem Abschnitt erfahren Sie, wie Sie eine komplexe Benutzeroberfläche für die Produktliste mit benutzerdefiniertem Design erstellen, indem Sie Widgets mit einem oder mehreren untergeordneten Layouts verwenden.

Befolgen Sie zu diesem Zweck die unten angegebene Reihenfolge -

  • Erstellen Sie eine neue Flutter- Anwendung in Android Studio, product_layout_app .

  • Ersetzen Sie den main.dart- Code durch den folgenden Code -

import 'package:flutter/material.dart'; 
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: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • Wir haben das MyHomePage- Widget erstellt, indem wir StatelessWidget anstelle des Standard- StatefulWidget erweitert und dann den entsprechenden Code entfernt haben.

  • Erstellen Sie nun ein neues Widget, ProductBox, gemäß dem unten angegebenen Design.

  • Der Code für die ProductBox lautet wie folgt.

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • Bitte beachten Sie Folgendes im Code -

  • ProductBox hat vier Argumente verwendet, wie unten angegeben -

    • Name - Produktname

    • Beschreibung - Produktbeschreibung

    • Preis - Preis des Produkts

    • Bild - Bild des Produkts

  • ProductBox verwendet sieben integrierte Widgets, wie unten angegeben -

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBox wird mit dem oben genannten Widget entwickelt. Die Anordnung oder Hierarchie des Widgets ist in der folgenden Abbildung angegeben.

  • Platzieren Sie nun ein Dummy-Image (siehe unten) für Produktinformationen im Assets-Ordner der Anwendung und konfigurieren Sie den Assets-Ordner in der Datei pubspec.yaml wie unten gezeigt -

assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png

iPhone.png

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

Verwenden Sie schließlich das ProductBox- Widget im MyHomePage- Widget wie unten angegeben -

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

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • Hier haben wir ProductBox als untergeordnete Elemente des ListView- Widgets verwendet.

  • Der vollständige Code (main.dart) der Produktlayoutanwendung (product_layout_app) lautet wie folgt:

import 'package:flutter/material.dart'; 
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: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

Die endgültige Ausgabe der Anwendung lautet wie folgt:

Gesten sind in erster Linie eine Möglichkeit für einen Benutzer, mit einer mobilen Anwendung (oder einem berührungsbasierten Gerät) zu interagieren. Gesten werden im Allgemeinen als jede physische Handlung / Bewegung eines Benutzers definiert, um eine bestimmte Steuerung des mobilen Geräts zu aktivieren. Gesten sind so einfach wie das Tippen auf den Bildschirm des Mobilgeräts, um komplexere Aktionen auszuführen, die in Spieleanwendungen verwendet werden.

Einige der weit verbreiteten Gesten werden hier erwähnt -

  • Tap - Berühren Sie kurz die Oberfläche des Geräts mit der Fingerspitze und lassen Sie dann die Fingerspitze los.

  • Double Tap - Zweimal in kurzer Zeit tippen.

  • Drag - Berühren Sie die Oberfläche des Geräts mit der Fingerspitze, bewegen Sie die Fingerspitze gleichmäßig und lassen Sie die Fingerspitze schließlich los.

  • Flick - Ähnlich wie beim Ziehen, aber auf eine schnellere Art und Weise.

  • Pinch - Drücken Sie mit zwei Fingern auf die Oberfläche des Geräts.

  • Spread/Zoom - Gegenüber dem Kneifen.

  • Panning - Berühren Sie die Oberfläche des Geräts mit der Fingerspitze und bewegen Sie es in eine beliebige Richtung, ohne die Fingerspitze loszulassen.

Flutter bietet durch sein exklusives Widget eine hervorragende Unterstützung für alle Arten von Gesten. GestureDetector. GestureDetector ist ein nicht visuelles Widget, das hauptsächlich zum Erkennen der Geste des Benutzers verwendet wird. Um eine Geste zu identifizieren, die auf ein Widget abzielt, kann das Widget im GestureDetector-Widget platziert werden. GestureDetector erfasst die Geste und sendet basierend auf der Geste mehrere Ereignisse aus.

Einige der Gesten und die entsprechenden Ereignisse sind unten angegeben -

  • Tap
    • onTapDown
    • onTapUp
    • onTap
    • onTapCancel
  • Doppeltippen
    • onDoubleTap
  • Lange drücken
    • onLongPress
  • Vertikaler Widerstand
    • onVerticalDragStart
    • onVerticalDragUpdate
    • onVerticalDragEnd
  • Horizontales Ziehen
    • onHorizontalDragStart
    • onHorizontalDragUpdate
    • onHorizontalDragEnd
  • Pan
    • onPanStart
    • onPanUpdate
    • onPanEnd

Lassen Sie uns nun die Hallo-Welt-Anwendung so ändern, dass sie eine Gestenerkennungsfunktion enthält, und versuchen, das Konzept zu verstehen.

  • Ändern Sie den Hauptinhalt des MyHomePage- Widgets wie unten gezeigt -

body: Center( 
   child: GestureDetector( 
      onTap: () { 
         _showDialog(context); 
      }, 
      child: Text( 'Hello World', ) 
   ) 
),
  • Beachten Sie, dass wir hier das GestureDetector- Widget über dem Text-Widget in der Widget-Hierarchie platziert, das onTap-Ereignis erfasst und schließlich ein Dialogfenster angezeigt haben.

  • Implementieren Sie die Funktion * _showDialog *, um einen Dialog anzuzeigen, wenn der Benutzer die Nachricht "Hallo Welt" auf die Registerkarte setzt . Es verwendet das generische Widget showDialog und AlertDialog , um ein neues Dialog-Widget zu erstellen. Der Code wird unten angezeigt -

// user defined function void _showDialog(BuildContext context) { 
   // flutter defined function 
   showDialog( 
      context: context, builder: (BuildContext context) { 
         // return object of type Dialog
         return AlertDialog( 
            title: new Text("Message"), 
            content: new Text("Hello World"),   
            actions: <Widget>[ 
               new FlatButton( 
                  child: new Text("Close"),  
                  onPressed: () {   
                     Navigator.of(context).pop();  
                  }, 
               ), 
            ], 
         ); 
      }, 
   ); 
}
  • Die Anwendung wird mithilfe der Hot-Reload-Funktion auf dem Gerät neu geladen. Klicken Sie nun einfach auf die Nachricht "Hallo Welt" und der folgende Dialog wird angezeigt:

  • Schließen Sie nun den Dialog, indem Sie im Dialog auf die Option zum Schließen klicken .

  • Der vollständige Code (main.dart) lautet wie folgt:

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application.    
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application', 
         theme: ThemeData( primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   // user defined function 
   void _showDialog(BuildContext context) { 
      // flutter defined function showDialog( 
         context: context, builder: (BuildContext context) { 
            // return object of type Dialog return AlertDialog(
               title: new Text("Message"), 
               content: new Text("Hello World"),   
               actions: <Widget>[
                  new FlatButton(
                     child: new Text("Close"), 
                     onPressed: () {   
                        Navigator.of(context).pop();  
                     }, 
                  ), 
               ],
            );
         },
      );
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center(
            child: GestureDetector( 
               onTap: () {
                  _showDialog(context);
               },
            child: Text( 'Hello World', )
            )
         ),
      );
   }
}

Schließlich bietet Flutter über das Listener- Widget auch einen Mechanismus zur Erkennung von Gesten auf niedriger Ebene . Es erkennt alle Benutzerinteraktionen und löst dann die folgenden Ereignisse aus:

  • PointerDownEvent
  • PointerMoveEvent
  • PointerUpEvent
  • PointerCancelEvent

Flutter bietet auch eine kleine Reihe von Widgets für bestimmte und erweiterte Gesten. Die Widgets sind unten aufgeführt -

  • Dismissible - Unterstützt die Flick-Geste, um das Widget zu schließen.

  • Draggable - Unterstützt die Drag-Geste zum Verschieben des Widgets.

  • LongPressDraggable - Unterstützt die Drag-Geste zum Verschieben eines Widgets, wenn das übergeordnete Widget ebenfalls ziehbar ist.

  • DragTarget- Akzeptiert alle ziehbaren Widgets

  • IgnorePointer - Blendet das Widget und seine untergeordneten Elemente vor dem Gestenerkennungsprozess aus.

  • AbsorbPointer - Stoppt den Gestenerkennungsprozess selbst, sodass überlappende Widgets auch nicht am Gestenerkennungsprozess teilnehmen können und daher kein Ereignis ausgelöst wird.

  • Scrollable - Unterstützt das Scrollen des im Widget verfügbaren Inhalts.

Das Verwalten des Status in einer Anwendung ist einer der wichtigsten und notwendigsten Prozesse im Lebenszyklus einer Anwendung.

Betrachten wir eine einfache Warenkorbanwendung.

  • Der Benutzer meldet sich mit seinen Anmeldeinformationen bei der Anwendung an.

  • Sobald der Benutzer angemeldet ist, sollte die Anwendung die angemeldeten Benutzerdetails auf dem gesamten Bildschirm beibehalten.

  • Wenn der Benutzer ein Produkt auswählt und in einem Warenkorb speichert, sollten die Warenkorbinformationen zwischen den Seiten bestehen bleiben, bis der Benutzer den Warenkorb ausgecheckt hat.

  • Benutzer- und deren Warenkorbinformationen werden in jeder Instanz als Status der Anwendung in dieser Instanz bezeichnet.

Eine Statusverwaltung kann basierend auf der Dauer des jeweiligen Status in einer Anwendung in zwei Kategorien unterteilt werden.

  • Ephemeral- Halten Sie einige Sekunden wie den aktuellen Status einer Animation oder eine einzelne Seite wie die aktuelle Bewertung eines Produkts an. Flutter unterstützt seine durch StatefulWidget.

  • app state- Als letztes für die gesamte Anwendung wie angemeldete Benutzerdetails, Warenkorbinformationen usw. unterstützt Flutter das durch scoped_model.

Navigation und Routing

In jeder Anwendung definiert das Navigieren von einer Seite / einem Bildschirm zu einer anderen den Arbeitsablauf der Anwendung. Die Art und Weise, wie die Navigation einer Anwendung gehandhabt wird, wird als Routing bezeichnet. Flutter bietet eine grundlegende Routing-Klasse - MaterialPageRoute und zwei Methoden - Navigator.push und Navigator.pop -, um den Arbeitsablauf einer Anwendung zu definieren.

MaterialPageRoute

MaterialPageRoute ist ein Widget, mit dem die Benutzeroberfläche gerendert wird, indem der gesamte Bildschirm durch eine plattformspezifische Animation ersetzt wird.

MaterialPageRoute(builder: (context) => Widget())

Hier akzeptiert der Builder eine Funktion zum Erstellen seines Inhalts, indem er den aktuellen Kontext der Anwendung ergänzt.

Navigation.push

Navigation.push wird verwendet, um mit dem MaterialPageRoute-Widget zu einem neuen Bildschirm zu navigieren.

Navigator.push( context, MaterialPageRoute(builder: (context) => Widget()), );

Navigation.pop

Navigation.pop wird verwendet, um zum vorherigen Bildschirm zu navigieren.

Navigator.pop(context);

Lassen Sie uns eine neue Anwendung erstellen, um das Navigationskonzept besser zu verstehen.

Erstellen Sie eine neue Flutter-Anwendung in Android Studio, product_nav_app

  • Kopieren Sie den Assets-Ordner von product_nav_app nach product_state_app und fügen Sie Assets in die Datei pubspec.yaml ein.

flutter:
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Ersetzen Sie den Standard-Startcode (main.dart) durch unseren Startcode.

import 'package:flutter/material.dart'; 
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: 'Product state demo home page'
         ),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: Text('Hello World',)
         ), 
      ); 
   } 
}
  • Lassen Sie uns eine Produktklasse erstellen, um die Produktinformationen zu organisieren.

class Product { 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
}
  • Schreiben wir eine Methode getProducts in die Produktklasse, um unsere Dummy-Produktdatensätze zu generieren.

static List<Product> getProducts() {
   List<Product> items = <Product>[]; 
   
   items.add(
      Product( 
         "Pixel", 
         "Pixel is the most feature-full phone ever", 800, 
         "pixel.png"
      )
   ); 
   items.add(
      Product(
         "Laptop", 
         "Laptop is most productive development tool", 
         2000, "
         laptop.png"
      )
   ); 
   items.add(
      Product( 
         "Tablet", 
         "Tablet is the most useful device ever for meeting", 
         1500, 
         "tablet.png"
      )
   ); 
   items.add(
      Product( 
         "Pendrive", 
         "Pendrive is useful storage medium",
         100, 
         "pendrive.png"
      )
   ); 
   items.add(
      Product( 
         "Floppy Drive", 
         "Floppy drive is useful rescue storage medium", 
         20, 
         "floppy.png"
      )
   ); 
   return items; 
}
import product.dart in main.dart
import 'Product.dart';
  • Nehmen wir unser neues Widget RatingBox auf.

class RatingBox extends StatefulWidget {
   @override 
   _RatingBoxState createState() =>_RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> {
   int _rating = 0; 
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   } 
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   }
   void _setRatingAsThree() {
      setState(() {
         _rating = 3;
      });
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 2? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   }
}
  • Lassen Sie uns unser ProductBox-Widget so ändern, dass es mit unserer neuen Produktklasse funktioniert.

class ProductBox extends StatelessWidget {    
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), 
                        child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[
                              Text(this.item.name, 
                              style: TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   }
}

Lassen Sie uns unser MyHomePage-Widget neu schreiben, um mit dem Produktmodell zu arbeiten und alle Produkte mit ListView aufzulisten.

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( appBar: AppBar(title: Text("Product Navigation")), 
      body: ListView.builder( 
         itemCount: items.length, 
         itemBuilder: (context, index) {
            return GestureDetector( 
               child: ProductBox(item: items[index]), 
               onTap: () { 
                  Navigator.push( 
                     context, MaterialPageRoute( 
                        builder: (context) => ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      )); 
   } 
}

Hier haben wir MaterialPageRoute verwendet, um zur Produktdetailseite zu navigieren.

  • Fügen wir nun ProductPage hinzu, um die Produktdetails anzuzeigen.

class ProductPage extends StatelessWidget { 
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container(
               padding: EdgeInsets.all(0), 
               child: Column(
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded(
                        child: Container(
                           padding: EdgeInsets.all(5), 
                           child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[
                                 Text(
                                    this.item.name, style: TextStyle(
                                       fontWeight: FontWeight.bold
                                    )
                                 ), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(),
                              ], 
                           )
                        )
                     )
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}

Der vollständige Code der Anwendung lautet wie folgt:

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class Product {
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
   
   static List<Product> getProducts() {
      List<Product> items = <Product>[]; 
      items.add(
         Product(
            "Pixel", 
            "Pixel is the most featureful phone ever", 
            800, 
            "pixel.png"
         )
      );
      items.add(
         Product(
            "Laptop", 
            "Laptop is most productive development tool", 
            2000, 
            "laptop.png"
         )
      ); 
      items.add(
         Product(
            "Tablet", 
            "Tablet is the most useful device ever for meeting", 
            1500, 
            "tablet.png"
         )
      ); 
      items.add(
         Product( 
            "Pendrive", 
            "iPhone is the stylist phone ever", 
            100, 
            "pendrive.png"
         )
      ); 
      items.add(
         Product(
            "Floppy Drive", 
            "iPhone is the stylist phone ever", 
            20, 
            "floppy.png"
         )
      ); 
      items.add(
         Product(
            "iPhone", 
            "iPhone is the stylist phone ever", 
            1000, 
            "iphone.png"
         )
      ); 
      return items; 
   }
}
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: 'Product Navigation demo home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Navigation")), 
         body: ListView.builder( 
            itemCount: items.length, 
            itemBuilder: (context, index) { 
               return GestureDetector( 
                  child: ProductBox(item: items[index]), 
                  onTap: () { 
                     Navigator.push( 
                        context, 
                        MaterialPageRoute( 
                           builder: (context) => ProductPage(item: items[index]), 
                        ), 
                     ); 
                  }, 
               ); 
            }, 
         )
      ); 
   }
} 
class ProductPage extends StatelessWidget {
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container( 
               padding: EdgeInsets.all(0), 
               child: Column( 
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[ 
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class RatingBox extends StatefulWidget { 
   @override 
   _RatingBoxState createState() => _RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> { 
   int _rating = 0;
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   }
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   } 
   void _setRatingAsThree() { 
      setState(() {
         _rating = 3; 
      }); 
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1 ? Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton( 
                  icon: (
                     _rating >= 2 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     )
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
} 
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  ) 
               ]
            ), 
         )
      ); 
   } 
}

Führen Sie die Anwendung aus und klicken Sie auf eines der Produktelemente. Es wird die Seite mit den relevanten Details angezeigt. Wir können zur Startseite wechseln, indem wir auf die Schaltfläche "Zurück" klicken. Die Produktlistenseite und die Produktdetailseite der Anwendung werden wie folgt angezeigt:

Animation ist ein komplexer Vorgang in jeder mobilen Anwendung. Trotz seiner Komplexität verbessert Animation die Benutzererfahrung auf ein neues Niveau und bietet eine umfassende Benutzerinteraktion. Animation wird aufgrund ihres Reichtums zu einem integralen Bestandteil moderner mobiler Anwendungen. Das Flutter-Framework erkennt die Bedeutung der Animation und bietet ein einfaches und intuitives Framework für die Entwicklung aller Arten von Animationen.

Einführung

Animation ist ein Prozess, bei dem eine Reihe von Bildern / Bildern in einer bestimmten Reihenfolge innerhalb einer bestimmten Dauer angezeigt wird, um eine Illusion von Bewegung zu erzeugen. Die wichtigsten Aspekte der Animation sind:

  • Die Animation hat zwei unterschiedliche Werte: Startwert und Endwert. Die Animation beginnt von Anfang Wert und geht durch eine Reihe von Zwischenwerten und schließlich bei Endwerte endet. Um beispielsweise ein Widget zum Ausblenden zu animieren, ist der Anfangswert die volle Deckkraft und der Endwert die Deckkraft Null.

  • Die Zwischenwerte können linearer oder nichtlinearer (Kurve) Natur sein und können konfiguriert werden. Verstehen Sie, dass die Animation so funktioniert, wie sie konfiguriert ist. Jede Konfiguration verleiht der Animation ein anderes Gefühl. Das Ausblenden eines Widgets ist beispielsweise linear, während das Abprallen eines Balls nicht linear ist.

  • Die Dauer des Animationsprozesses beeinflusst die Geschwindigkeit (Langsamkeit oder Schnelligkeit) der Animation.

  • Die Möglichkeit, den Animationsprozess zu steuern, z. B. das Starten der Animation, das Stoppen der Animation, das Wiederholen der Animation, um die Anzahl festzulegen, das Umkehren des Animationsprozesses usw.

  • In Flutter führt das Animationssystem keine echte Animation aus. Stattdessen werden nur die Werte bereitgestellt, die für jedes Bild zum Rendern der Bilder erforderlich sind.

Animationsbasierte Klassen

Das Flatter-Animationssystem basiert auf Animationsobjekten. Die Kernanimationsklassen und ihre Verwendung sind wie folgt:

Animation

Erzeugt interpolierte Werte zwischen zwei Zahlen über eine bestimmte Dauer. Die häufigsten Animationsklassen sind -

  • Animation<double> - Werte zwischen zwei Dezimalzahlen interpolieren

  • Animation<Color> - Interpolieren Sie Farben zwischen zwei Farben

  • Animation<Size> - Interpolieren Sie Größen zwischen zwei Größen

  • AnimationController- Spezielles Animationsobjekt zur Steuerung der Animation selbst. Es generiert neue Werte, wenn die Anwendung für einen neuen Frame bereit ist. Es unterstützt lineare Animationen und der Wert beginnt bei 0,0 bis 1,0

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);

Hier steuert der Controller die Animation und die Option Dauer steuert die Dauer des Animationsprozesses. vsync ist eine spezielle Option zur Optimierung der in der Animation verwendeten Ressource.

CurvedAnimation

Ähnlich wie AnimationController, unterstützt jedoch nichtlineare Animationen. CurvedAnimation kann zusammen mit dem Animationsobjekt wie folgt verwendet werden:

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)

Tween <T>

Abgeleitet von Animatable <T> und zum Generieren von Zahlen zwischen zwei beliebigen Zahlen außer 0 und 1. Es kann zusammen mit dem Animationsobjekt verwendet werden, indem die Animationsmethode verwendet und das eigentliche Animationsobjekt übergeben wird.

AnimationController controller = AnimationController( 
   duration: const Duration(milliseconds: 1000), 
vsync: this); Animation<int> customTween = IntTween(
   begin: 0, end: 255).animate(controller);
  • Tween kann auch zusammen mit CurvedAnimation wie folgt verwendet werden -

AnimationController controller = AnimationController(
   duration: const Duration(milliseconds: 500), vsync: this); 
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); 
Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve);

Hier ist der Controller der eigentliche Animations-Controller. Die Kurve gibt den Typ der Nichtlinearität an und das customTween bietet einen benutzerdefinierten Bereich von 0 bis 255.

Arbeitsablauf der Flatteranimation

Der Arbeitsablauf der Animation ist wie folgt:

  • Definieren und starten Sie den Animations-Controller im initState des StatefulWidget.

AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = Tween<double>(begin: 0, end: 300).animate(controller); 
controller.forward();
  • Fügen Sie einen animationsbasierten Listener und addListener hinzu, um den Status des Widgets zu ändern.

animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
   setState(() { 
      // The state that has changed here is the animation object’s value. 
   }); 
});
  • Mit eingebauten Widgets, AnimatedWidget und AnimatedBuilder können Sie diesen Vorgang überspringen. Beide Widgets akzeptieren Animationsobjekte und erhalten aktuelle Werte, die für die Animation erforderlich sind.

  • Rufen Sie die Animationswerte während des Erstellungsprozesses des Widgets ab und wenden Sie sie anstelle des ursprünglichen Werts auf Breite, Höhe oder eine relevante Eigenschaft an.

child: Container( 
   height: animation.value, 
   width: animation.value, 
   child: <Widget>, 
)

Arbeitsanwendung

Lassen Sie uns eine einfache animationsbasierte Anwendung schreiben, um das Konzept der Animation im Flutter-Framework zu verstehen.

  • Erstellen Sie eine neue Flutter- Anwendung in Android Studio, product_animation_app.

  • Kopieren Sie den Assets-Ordner von product_nav_app nach product_animation_app und fügen Sie Assets in die Datei pubspec.yaml ein.

flutter: 
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Entfernen Sie den Standardstartcode (main.dart).

  • Import und grundlegende Hauptfunktion hinzufügen.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp());
  • Erstellen Sie das von StatefulWidgtet abgeleitete MyApp-Widget.

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
}
  • Erstellen Sie das Widget _MyAppState, implementieren Sie initState und entsorgen Sie es zusätzlich zur Standarderstellungsmethode.

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { 
   Animation<double> animation; 
   AnimationController controller; 
   @override void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this
      ); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp(
         title: 'Flutter Demo',
         theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,)
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose();
   }
}

Hier,

  • In der initState-Methode haben wir ein Animations-Controller-Objekt (Controller) und ein Animationsobjekt (Animation) erstellt und die Animation mit controller.forward gestartet.

  • Bei der Entsorgungsmethode haben wir das Animations-Controller-Objekt (Controller) entsorgt.

  • Senden Sie in der Erstellungsmethode die Animation über den Konstruktor an das MyHomePage-Widget. Jetzt kann das MyHomePage-Widget das Animationsobjekt verwenden, um seinen Inhalt zu animieren.

  • Fügen Sie nun das ProductBox-Widget hinzu

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image})
      : super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row( 
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.name, style: 
                                 TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.description), 
                                 Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      ); 
   }
}
  • Erstellen Sie ein neues Widget, MyAnimatedWidget, um einfache Überblendungsanimationen mit Deckkraft zu erstellen.

class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
      
   final Widget child; 
   final Animation<double> animation; 
   
   Widget build(BuildContext context) => Center( 
   child: AnimatedBuilder(
      animation: animation, 
      builder: (context, child) => Container( 
         child: Opacity(opacity: animation.value, child: child), 
      ), 
      child: child), 
   ); 
}
  • Hier haben wir AniatedBuilder verwendet, um unsere Animation zu erstellen. AnimatedBuilder ist ein Widget, das seinen Inhalt erstellt und gleichzeitig die Animation ausführt. Es akzeptiert ein Animationsobjekt, um den aktuellen Animationswert abzurufen. Wir haben den Animationswert animation.value verwendet, um die Deckkraft des untergeordneten Widgets festzulegen. Tatsächlich animiert das Widget das untergeordnete Widget mithilfe des Deckkraftkonzepts.

  • Erstellen Sie abschließend das MyHomePage-Widget und animieren Sie den Inhalt mithilfe des Animationsobjekts.

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title, this.animation}) : super(key: key); 
   
   final String title; 
   final Animation<double> 
   animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")),body: ListView(
            shrinkWrap: true,
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), opacity: animation
               ), 
               MyAnimatedWidget(child: ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), animation: animation), 
               ProductBox(
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ),
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ),
            ],
         )
      );
   }
}

Hier haben wir FadeAnimation und MyAnimationWidget verwendet, um die ersten beiden Elemente in der Liste zu animieren. FadeAnimation ist eine integrierte Animationsklasse, mit der wir das untergeordnete Element mithilfe des Opazitätskonzepts animiert haben.

  • Der vollständige Code lautet wie folgt:

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
} 
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
   Animation<double> animation; 
   AnimationController controller; 
   
   @override 
   void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,) 
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose(); 
   } 
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title, this.animation}): super(key: key);
   final String title; 
   final Animation<double> animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), 
                  opacity: animation
               ), 
               MyAnimatedWidget(
                  child: ProductBox( 
                     name: "Pixel", 
                     description: "Pixel is the most featureful phone ever", 
                     price: 800, 
                     image: "pixel.png"
                  ), 
                  animation: animation
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet",
                  description: "Tablet is the most useful device ever for meeting",
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ], 
         )
      ); 
   } 
} 
class ProductBox extends StatelessWidget { 
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded(
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ), 
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  ) 
               ]
            )
         )
      ); 
   } 
}
class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
   final Widget child; 
   final Animation<double> animation; 
 
   Widget build(BuildContext context) => Center( 
      child: AnimatedBuilder(
         animation: animation, 
         builder: (context, child) => Container( 
            child: Opacity(opacity: animation.value, child: child), 
         ), 
         child: child
      ), 
   ); 
}
  • Kompilieren Sie die Anwendung und führen Sie sie aus, um die Ergebnisse anzuzeigen. Die ursprüngliche und endgültige Version der Anwendung lautet wie folgt:

Flutter bietet einen allgemeinen Rahmen für den Zugriff auf plattformspezifische Funktionen. Dadurch kann der Entwickler die Funktionalität des Flutter- Frameworks mithilfe von plattformspezifischem Code erweitern. Auf plattformspezifische Funktionen wie Kamera, Akkuladestand, Browser usw. kann über das Framework problemlos zugegriffen werden.

Die allgemeine Idee, auf den plattformspezifischen Code zuzugreifen, besteht in einem einfachen Messaging-Protokoll. Flattercode, Client und Plattformcode sowie Host werden an einen gemeinsamen Nachrichtenkanal gebunden. Der Client sendet eine Nachricht über den Nachrichtenkanal an den Host. Der Host hört auf den Nachrichtenkanal, empfängt die Nachricht und führt die erforderlichen Funktionen aus. Anschließend gibt er das Ergebnis über den Nachrichtenkanal an den Client zurück.

Die plattformspezifische Codearchitektur ist im folgenden Blockdiagramm dargestellt.

Das Messaging-Protokoll verwendet einen Standard-Nachrichtencodec (StandardMessageCodec-Klasse), der die binäre Serialisierung von JSON-ähnlichen Werten wie Zahlen, Zeichenfolgen, Booleschen Werten usw. unterstützt. Die Serialisierung und De-Serialisierung funktioniert transparent zwischen dem Client und dem Host.

Lassen Sie uns eine einfache Anwendung schreiben, um einen Browser mit Android SDK zu öffnen und zu verstehen, wie

  • Erstellen Sie eine neue Flutter-Anwendung in Android Studio, flutter_browser_app

  • Ersetzen Sie den main.dart-Code durch den folgenden Code -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Flutter Demo Home Page'),
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: null, 
            ), 
         ), 
      ); 
   }
}
  • Hier haben wir eine neue Schaltfläche erstellt, um den Browser zu öffnen und die onPressed-Methode auf null zu setzen.

  • Importieren Sie nun die folgenden Pakete:

import 'dart:async'; 
import 'package:flutter/services.dart';
  • Hier enthält services.dart die Funktionalität zum Aufrufen von plattformspezifischem Code.

  • Erstellen Sie einen neuen Nachrichtenkanal im MyHomePage-Widget.

static const platform = const 
MethodChannel('flutterapp.tutorialspoint.com/browser');
  • Schreiben Sie eine Methode, _openBrowser, um die plattformspezifische Methode aufzurufen, openBrowser-Methode über den Nachrichtenkanal.

Future<void> _openBrowser() async { 
   try {
      final int result = await platform.invokeMethod(
         'openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         }
      ); 
   } 
   on PlatformException catch (e) { 
      // Unable to open the browser 
      print(e); 
   }
}

Hier haben wir platform.invokeMethod verwendet, um openBrowser aufzurufen (wird in den folgenden Schritten erläutert). openBrowser hat ein Argument, URL, um eine bestimmte URL zu öffnen.

  • Ändern Sie den Wert der onPressed-Eigenschaft des RaisedButton von null in _openBrowser.

onPressed: _openBrowser,
  • Öffnen Sie MainActivity.java (im Android-Ordner) und importieren Sie die gewünschte Bibliothek -

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant;
  • Schreiben Sie eine Methode, openBrowser, um einen Browser zu öffnen

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = this; 
   if (activity == null) { 
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground 
      activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • Legen Sie nun den Kanalnamen in der MainActivity-Klasse fest -

private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser";
  • Schreiben Sie androidspezifischen Code, um die Nachrichtenbehandlung in der onCreate-Methode festzulegen.

new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( 
   new MethodCallHandler() { 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("openBrowser")) {
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
});

Hier haben wir einen Nachrichtenkanal mit der MethodChannel-Klasse erstellt und die MethodCallHandler-Klasse verwendet, um die Nachricht zu verarbeiten. onMethodCall ist die eigentliche Methode, die dafür verantwortlich ist, den richtigen plattformspezifischen Code durch Überprüfen der Nachricht aufzurufen. Die onMethodCall-Methode extrahiert die URL aus der Nachricht und ruft den openBrowser nur auf, wenn der Methodenaufruf openBrowser lautet. Andernfalls wird die notImplemented-Methode zurückgegeben.

Der vollständige Quellcode der Anwendung lautet wie folgt:

main.dart

MainActivity.java

package com.tutorialspoint.flutterapp.flutter_browser_app; 

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 
import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant; 

public class MainActivity extends FlutterActivity { 
   private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser"; 
   @Override 
   protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      GeneratedPluginRegistrant.registerWith(this); 
      new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
         new MethodCallHandler() {
            @Override 
            public void onMethodCall(MethodCall call, Result result) {
               String url = call.argument("url"); 
               if (call.method.equals("openBrowser")) { 
                  openBrowser(call, result, url); 
               } else { 
                  result.notImplemented(); 
               }
            }
         }
      ); 
   }
   private void openBrowser(MethodCall call, Result result, String url) {
      Activity activity = this; if (activity == null) {
         result.error(
            "ACTIVITY_NOT_AVAILABLE", "Browser cannot be opened without foreground activity", null
         ); 
         return; 
      } 
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   }
}

main.dart

import 'package:flutter/material.dart'; 
import 'dart:async'; 
import 'package:flutter/services.dart'; 

void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget {
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   static const platform = const MethodChannel('flutterapp.tutorialspoint.com/browser'); 
   Future<void> _openBrowser() async {
      try {
         final int result = await platform.invokeMethod('openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         });
      }
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      } 
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: _openBrowser, 
            ), 
         ),
      );
   }
}

Führen Sie die Anwendung aus und klicken Sie auf die Schaltfläche Browser öffnen. Sie können sehen, dass der Browser gestartet ist. Die Browser-App - Homepage ist wie im Screenshot hier gezeigt -

Der Zugriff auf iOS-spezifischen Code ähnelt dem auf der Android-Plattform, verwendet jedoch iOS-spezifische Sprachen - Objective-C oder Swift und iOS SDK. Ansonsten entspricht das Konzept dem der Android-Plattform.

Lassen Sie uns dieselbe Anwendung wie im vorherigen Kapitel auch für die iOS-Plattform schreiben.

  • Lassen Sie uns eine neue Anwendung in Android Studio (macOS) erstellen , flutter_browser_ios_app

  • Befolgen Sie die Schritte 2 bis 6 wie im vorherigen Kapitel.

  • Starten Sie XCode und klicken Sie auf File → Open

  • Wählen Sie das xcode-Projekt im ios-Verzeichnis unseres Flatterprojekts.

  • Öffnen Sie AppDelegate.m unter Runner → Runner path. Es enthält den folgenden Code -

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      // [GeneratedPluginRegistrant registerWithRegistry:self];
      // Override point for customization after application launch.
      return [super application:application didFinishLaunchingWithOptions:launchOptions];
   } 
@end
  • Wir haben eine Methode hinzugefügt, openBrowser, um den Browser mit der angegebenen URL zu öffnen. Es akzeptiert ein einzelnes Argument, URL.

- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
}
  • Suchen Sie in der didFinishLaunchingWithOptions-Methode den Controller und legen Sie ihn in der Controller-Variablen fest.

FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
  • Legen Sie in der didFinishLaunchingWithOptions-Methode den Browserkanal als flutterapp.tutorialspoint.com/browse - fest.

FlutterMethodChannel* browserChannel = [
   FlutterMethodChannel methodChannelWithName:
   @"flutterapp.tutorialspoint.com/browser" binaryMessenger:controller];
  • Erstellen Sie eine Variable, schwacheSelf und setzen Sie die aktuelle Klasse -

__weak typeof(self) weakSelf = self;
  • Implementieren Sie jetzt setMethodCallHandler. Rufen Sie openBrowser auf, indem Sie call.method abgleichen. Rufen Sie die URL ab, indem Sie call.arguments aufrufen, und übergeben Sie sie, während Sie openBrowser aufrufen.

[browserChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
   if ([@"openBrowser" isEqualToString:call.method]) { 
      NSString *url = call.arguments[@"url"];   
      [weakSelf openBrowser:url]; 
   } else { result(FlutterMethodNotImplemented); } 
}];
  • Der vollständige Code lautet wie folgt:

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application 
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   
   // custom code starts 
   FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; 
   FlutterMethodChannel* browserChannel = [
      FlutterMethodChannel methodChannelWithName:
      @"flutterapp.tutorialspoint.com /browser" binaryMessenger:controller]; 
   
   __weak typeof(self) weakSelf = self; 
   [browserChannel setMethodCallHandler:^(
      FlutterMethodCall* call, FlutterResult result) { 
      
      if ([@"openBrowser" isEqualToString:call.method]) { 
         NSString *url = call.arguments[@"url"];
         [weakSelf openBrowser:url]; 
      } else { result(FlutterMethodNotImplemented); } 
   }]; 
   // custom code ends 
   [GeneratedPluginRegistrant registerWithRegistry:self]; 
   
   // Override point for customization after application launch. 
   return [super application:application didFinishLaunchingWithOptions:launchOptions]; 
}
- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
} 
@end
  • Öffnen Sie die Projekteinstellung.

  • Gehe zu Capabilities und aktivieren Background Modes.

  • Hinzufügen *Background fetch und Remote Notification**.

  • Führen Sie nun die Anwendung aus. Es funktioniert ähnlich wie die Android-Version, aber der Safari-Browser wird anstelle von Chrome geöffnet.

Dart organisiert und teilt eine Reihe von Funktionen über das Paket. Dart Package ist einfach gemeinsam nutzbare Bibliotheken oder Module. Im Allgemeinen ist das Dart-Paket dasselbe wie das der Dart-Anwendung, außer dass das Dart-Paket keinen Anwendungseinstiegspunkt hat, main.

Die allgemeine Struktur des Pakets (betrachten Sie ein Demopaket, my_demo_package) ist wie folgt:

  • lib/src/* - Private Dart-Code-Dateien.

  • lib/my_demo_package.dart- Haupt-Dart-Code-Datei. Es kann in eine Anwendung importiert werden als -

import 'package:my_demo_package/my_demo_package.dart'
  • Andere private Codedateien können bei Bedarf in die Hauptcodedatei (my_demo_package.dart) exportiert werden, wie unten gezeigt -

export src/my_private_code.dart
  • lib/*- Beliebig viele Dart-Codedateien, die in einer benutzerdefinierten Ordnerstruktur angeordnet sind. Auf den Code kann zugegriffen werden als:

import 'package:my_demo_package/custom_folder/custom_file.dart'
  • pubspec.yaml - Projektspezifikation wie die der Anwendung,

Alle Dart-Code-Dateien im Paket sind einfach Dart-Klassen, und es ist nicht besonders erforderlich, dass ein Dart-Code ihn in ein Paket aufnimmt.

Arten von Paketen

Da es sich bei Dart-Paketen im Grunde genommen um eine kleine Sammlung ähnlicher Funktionen handelt, kann sie anhand ihrer Funktionalität kategorisiert werden.

Dart-Paket

Generischer Dart-Code, der sowohl in der Web- als auch in der mobilen Umgebung verwendet werden kann. Zum Beispiel ist english_words ein solches Paket, das ungefähr 5000 Wörter enthält und grundlegende Dienstprogrammfunktionen wie Substantive (Substantive auf Englisch auflisten) und Silben (Anzahl der Silben in einem Wort angeben) enthält.

Flatterpaket

Generischer Dart-Code, der vom Flutter-Framework abhängt und nur in mobilen Umgebungen verwendet werden kann. Zum Beispiel ist fluro ein benutzerdefinierter Router für das Flattern. Dies hängt vom Flutter-Framework ab.

Flatter Plugin

Generischer Dart-Code, der sowohl vom Flutter-Framework als auch vom zugrunde liegenden Plattformcode (Android SDK oder iOS SDK) abhängt. Beispielsweise ist die Kamera ein Plugin für die Interaktion mit der Gerätekamera. Es hängt sowohl vom Flutter-Framework als auch vom zugrunde liegenden Framework ab, um Zugriff auf die Kamera zu erhalten.

Verwenden eines Dart-Pakets

Dart-Pakete werden gehostet und auf dem Live-Server veröffentlicht. https://pub.dartlang.org.Außerdem bietet Flutter ein einfaches Tool, Pub, um Dart-Pakete in der Anwendung zu verwalten. Die zur Verwendung als Paket erforderlichen Schritte lauten wie folgt:

  • Fügen Sie den Paketnamen und die benötigte Version wie unten gezeigt in die Datei pubspec.yaml ein.

dependencies: english_words: ^3.1.5
  • Die neueste Versionsnummer finden Sie auf dem Online-Server.

  • Installieren Sie das Paket mit dem folgenden Befehl in der Anwendung:

flutter packages get
  • Während der Entwicklung im Android Studio erkennt Android Studio Änderungen in der Datei pubspec.yaml und zeigt dem Entwickler eine Warnung für das Android Studio-Paket an, wie unten gezeigt.

  • Dart-Pakete können über die Menüoptionen in Android Studio installiert oder aktualisiert werden.

  • Importieren Sie die erforderliche Datei mit dem unten gezeigten Befehl und beginnen Sie zu arbeiten -

import 'package:english_words/english_words.dart';
  • Verwenden Sie eine im Paket verfügbare Methode.

nouns.take(50).forEach(print);
  • Hier haben wir die Nomenfunktion verwendet, um die Top 50 Wörter zu erhalten und zu drucken.

Entwickeln Sie ein Flutter Plugin Package

Das Entwickeln eines Flutter-Plugins ähnelt dem Entwickeln einer Dart-Anwendung oder eines Dart-Pakets. Die einzige Ausnahme ist, dass das Plugin die System-API (Android oder iOS) verwendet, um die erforderlichen plattformspezifischen Funktionen zu erhalten.

Da wir bereits in den vorherigen Kapiteln gelernt haben, wie man auf Plattformcode zugreift, entwickeln wir ein einfaches Plugin, my_browser, um den Entwicklungsprozess des Plugins zu verstehen. Die Funktionalität des my_browser-Plugins besteht darin, dass die Anwendung die angegebene Website im plattformspezifischen Browser öffnen kann.

  • Starten Sie Android Studio.

  • Klicken File → New Flutter Project und wählen Sie die Option Flutter Plugin.

  • Sie können ein Auswahlfenster für das Flutter-Plugin sehen, wie hier gezeigt -

  • Geben Sie my_browser als Projektnamen ein und klicken Sie auf Weiter.

  • Geben Sie den Plugin-Namen und andere Details wie hier gezeigt in das Fenster ein -

  • Geben Sie in das unten gezeigte Fenster die Unternehmensdomäne flutterplugins.tutorialspoint.com ein und klicken Sie dann auf Finish. Es wird ein Startcode generiert, um unser neues Plugin zu entwickeln.

  • Öffnen Sie die Datei my_browser.dart und schreiben Sie eine Methode, openBrowser, um die plattformspezifische openBrowser-Methode aufzurufen.

Future<void> openBrowser(String urlString) async { 
   try {
      final int result = await _channel.invokeMethod(
         'openBrowser', <String, String>{ 'url': urlString }
      );
   }
   on PlatformException catch (e) { 
      // Unable to open the browser print(e); 
   } 
}
  • Öffnen Sie die Datei MyBrowserPlugin.java und importieren Sie die folgenden Klassen:

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle;
  • Hier müssen wir die Bibliothek importieren, die zum Öffnen eines Browsers von Android erforderlich ist.

  • Fügen Sie eine neue private Variable mRegistrar vom Typ Registrar in der MyBrowserPlugin-Klasse hinzu.

private final Registrar mRegistrar;
  • Hier wird Registrar verwendet, um Kontextinformationen des aufrufenden Codes abzurufen.

  • Fügen Sie einen Konstruktor hinzu, um Registrar in der MyBrowserPlugin-Klasse festzulegen.

private MyBrowserPlugin(Registrar registrar) { 
   this.mRegistrar = registrar; 
}
  • Ändern Sie registerWith, um unseren neuen Konstruktor in die MyBrowserPlugin-Klasse aufzunehmen.

public static void registerWith(Registrar registrar) { 
   final MethodChannel channel = new MethodChannel(registrar.messenger(), "my_browser"); 
   MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
   channel.setMethodCallHandler(instance); 
}
  • Ändern Sie onMethodCall so, dass die openBrowser-Methode in die MyBrowserPlugin-Klasse aufgenommen wird.

@Override 
public void onMethodCall(MethodCall call, Result result) { 
   String url = call.argument("url");
   if (call.method.equals("getPlatformVersion")) { 
      result.success("Android " + android.os.Build.VERSION.RELEASE); 
   } 
   else if (call.method.equals("openBrowser")) { 
      openBrowser(call, result, url); 
   } else { 
      result.notImplemented(); 
   } 
}
  • Schreiben Sie die plattformspezifische openBrowser-Methode, um auf den Browser in der MyBrowserPlugin-Klasse zuzugreifen.

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = mRegistrar.activity(); 
   if (activity == null) {
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • Der vollständige Quellcode des my_browser-Plugins lautet wie folgt:

my_browser.dart

import 'dart:async'; 
import 'package:flutter/services.dart'; 

class MyBrowser {
   static const MethodChannel _channel = const MethodChannel('my_browser'); 
   static Future<String> get platformVersion async { 
      final String version = await _channel.invokeMethod('getPlatformVersion'); return version; 
   } 
   Future<void> openBrowser(String urlString) async { 
      try {
         final int result = await _channel.invokeMethod(
            'openBrowser', <String, String>{'url': urlString}); 
      } 
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      }
   }
}

MyBrowserPlugin.java

package com.tutorialspoint.flutterplugins.my_browser; 

import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugin.common.PluginRegistry.Registrar; 
import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

/** MyBrowserPlugin */ 
public class MyBrowserPlugin implements MethodCallHandler {
   private final Registrar mRegistrar; 
   private MyBrowserPlugin(Registrar registrar) { 
      this.mRegistrar = registrar; 
   } 
   /** Plugin registration. */
   public static void registerWith(Registrar registrar) {
      final MethodChannel channel = new MethodChannel(
         registrar.messenger(), "my_browser"); 
      MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
      channel.setMethodCallHandler(instance); 
   } 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("getPlatformVersion")) { 
         result.success("Android " + android.os.Build.VERSION.RELEASE); 
      } 
      else if (call.method.equals("openBrowser")) { 
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
   private void openBrowser(MethodCall call, Result result, String url) { 
      Activity activity = mRegistrar.activity(); 
      if (activity == null) {
         result.error("ACTIVITY_NOT_AVAILABLE",
            "Browser cannot be opened without foreground activity", null); 
         return; 
      }
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   } 
}
  • Erstellen Sie ein neues Projekt, my_browser_plugin_test , um unser neu erstelltes Plugin zu testen.

  • Öffnen Sie pubspec.yaml und legen Sie my_browser als Plugin-Abhängigkeit fest.

dependencies: 
   flutter: 
      sdk: flutter 
   my_browser: 
      path: ../my_browser
  • Android Studio benachrichtigt Sie, dass die Datei pubspec.yaml aktualisiert wird, wie in der unten angegebenen Warnung zum Android Studio-Paket gezeigt.

  • Klicken Sie auf die Option Abhängigkeiten abrufen. Android Studio holt das Paket aus dem Internet und konfiguriert es ordnungsgemäß für die Anwendung.

  • Öffnen Sie main.dart und fügen Sie das my_browser-Plugin wie folgt hinzu:

import 'package:my_browser/my_browser.dart';
  • Rufen Sie die openBrowser-Funktion über das my_browser-Plugin auf (siehe unten).

onPressed: () => MyBrowser().openBrowser("https://flutter.dev"),
  • Der vollständige Code des main.dart lautet wie folgt:

import 'package:flutter/material.dart'; 
import 'package:my_browser/my_browser.dart'; 

void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      );,
   }
} 
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton(
               child: Text('Open Browser'), 
               onPressed: () => MyBrowser().openBrowser("https://flutter.dev"), 
            ),
         ), 
      ); 
   }
}
  • Führen Sie die Anwendung aus und klicken Sie auf die Schaltfläche Browser öffnen, um sicherzustellen, dass der Browser gestartet wird. Sie können eine Browser-App sehen - Startseite wie im folgenden Screenshot gezeigt -

Sie können eine Browser-App sehen - Browser-Bildschirm wie im folgenden Screenshot gezeigt -

  • Print
  •  Notizen hinzufügen
  •  Ein Lesezeichen auf diese Seite setzen
  •  Fehler melden
  •  Suggestions

Speichern Schließen