# Flutter 16.05.2024 ## Einleitung Flutter ist ein Open-Source-Framework, welches von Google entwickelt wurde und unterstützt wird. Auf Basis eines einzigen Codes kann eine Anwendung für verschiedene Plattformen generiert werden. Diese Plattformen sind unter anderem iOS, Android, Web und Desktop. Das unterscheidet Flutter von einer nativen App-Entwicklung, da diese nur eine Anwendung für eine bestimmte Plattform wie beispielsweise iOS. Das Framework Flutter benutzt die Programmiersprache Dart, welche auch von Google entwickelt wurde. [flutter_aws](https://aws.amazon.com/de/what-is/flutter/) ## Entwicklungs-Setup Zuerst muss Flutter gemäß dem [Installationsguide](https://docs.flutter.dev/get-started/install) installiert werden. Je nach Betriebssystem und Zielplattform gibt es hierfür unterschiedliche Anforderungen, darunter unter anderem Entwicklungsumgebungen und SDKs für iOS bzw. Android. Für iOS wird hierfür Xcode benötigt, für Android Android Studio oder IntelliJ IDEA. Unabhängig vom Betriebssystem wird sowohl das Dart SDK als auch das Flutter SDK benötigt. [Installation unter Ubuntu](https://docs.flutter.dev/get-started/install/linux/android?tab=download): 1. Installation der Abhängigkeiten ``` sudo apt-get update -y && sudo apt-get upgrade -y; sudo apt-get install -y curl git unzip xz-utils zip libglu1-mesa; sudo apt-get install \ libc6:i386 libncurses5:i386 \ libstdc++6:i386 lib32z1 \ libbz2-1.0:i386 ``` 2. [Download](https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.22.0-stable.tar.xz) Flutter 3. Entpacken der `.tar.xz` Datei nach `~/development/flutter` 4. Hinzufügen von Flutter zu PATH ``` echo 'export PATH="$HOME/development/flutter/bin:$PATH"' >> ~/.profile; source ~/.profile ``` 5. Installieren des Dart SDK - `sudo apt-get update && sudo apt-get install apt-transport-https` - `wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/dart.gpg` - `echo 'deb [signed-by=/usr/share/keyrings/dart.gpg arch=amd64] https://storage.googleapis.com/download.dartlang.org/linux/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list` - `sudo apt-get update && sudo apt-get install dart` ### Starten der Anwendung Die Anwendung kann in Android Studio geöffnet werden und in einem Virtuellen Android Gerät gestartet werden. ## Aufbau einer Flutter-Komponente In Flutter erstellen Entwickler dsa UI-Layout mit Hilfe von Widgets. Damit ist sozusagen alles, was ein Benutzer auf dem Bildschirm sieht, wie zum Beispiel ein Button oder Text, ein Widget. Widgets sind so konzipiert, dass Entwickler sie einfach anpassen können. Flutter erreicht das durch einen Kompositionsansatz. Das bedeutet, dass die meisten Widgets aus kleineren Widgets bestehen und die einfachsten Widgets bestimmte Zwecke haben. Die Widgets werden mit einer eigenen Grafik-Engine gerendert, anstatt sich auf die integrierten Widgets einer Plattform zu verlassen. Somit erleben Benutzer plattformübergreifend ein ähnliches Erscheinungsbild in der jeweiligen Anwendung. Ähnlich wie bei gängigen Webapps wird auch bei Flutter eine Baumstruktur verwendet, um die Komponenten zu organisieren. Jede Komponente wird als Widget bezeichnet und kann entweder ein Stateful- oder Stateless-Widget sein. Ein Stateless-Widget ist eine statische Komponente, die sich nicht während der Laufzeit der Flutter-Anwendung ändern kann und dementsprechend nie zu einem Rerender der Komponente führen kann. Im Gegensatz dazu kann ein Stateful-Widget verwendet werden, wenn sich Teile des UIs dynamisch während der Laufzeit ändern sollen. Diese Widgets können sich während der Laufzeit mehrfach neu builden. Das folgende Bild zeigt den beispielhaften Aufbau eines Flutter-Widget-Trees: ![Widget Tree](widget_tree.png) [Layouts in Flutter](https://docs.flutter.dev/ui/layout) [Difference between stateless and stateful widgets](https://blog.logrocket.com/difference-between-stateless-stateful-widgets-flutter/) ## Beispiel-Code unserer Flutter-App ### ListView Page ```dart @override Widget build(BuildContext context) { final List greenShades = [ Colors.green[50]!, Colors.green[100]!, Colors.green[200]!, Colors.green[300]!, Colors.green[400]!, Colors.green[500]!, Colors.green[600]!, Colors.green[700]!, Colors.green[800]!, Colors.green[900]!, ]; final List colors = greenShades; return ListView.builder( padding: const EdgeInsets.all(8), itemCount: greenShades.length, itemBuilder: (BuildContext context, int index) { return Container( height: MediaQuery .of(context) .size .height / greenShades.length, color: colors[index % colors.length], ); }, ); } ``` Diese simple `build`-Methode der Klasse `ListViewPage` erstellt eine ListView, die eine Liste von Containern mit den Farben aus der gegebenen Liste `greenShades` anzeigt. Die ListView wird mit einem `ListView.builder`-Widget erstellt, das die Properties `itemCount` und `itemBuilder` erfordert. Der `itemBuilder` ist eine Funktion mit zwei Parametern, die für jedes Item einen Container mit der gegebenen Hintergrundfarbe erstellt. ### Weather Page Mithilfe von weatherapi.com wird auf der Wetter-Seite der Flutter-Demo-Anwendung die aktuelle Wettervorhersage für eine gegebene Stadt abgerufen und angezeigt: ``` final response = await http.get( Uri.parse( 'https://api.weatherapi.com/v1/current.json?key=$apiKey&q=$_city&aqi=no'), ); ``` Nachdem eine erfolgreiche Antwort (Status Code 200) auf diese HTTP-Anfrage angekommen ist, wird der JSON-Body der Antwort weiter verarbeitet und die relevanten Informationen wie Temperatur und Wetterbeschreibung in Variablen gespeichert. Durch `setState` wird Flutter signalisiert, dass sich der State des Widgets verändert hat. Dadurch wird ein Rebuild gescheduled und anschließend die aktualisierten (bzw. in diesem Fall die neu dazugekommen Daten) im UI angezeigt. ``` if (response.statusCode == 200) { final data = json.decode(response.body); final current = data['current']; setState(() { _temperature = current['temp_c']; _description = current['condition']['text']; _icon = current['condition']['text']; }); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Fehler beim Abrufen der Wetterdaten.'), ), ); } ``` ### Interactive Viewer Mithilfe des Interactive Viewers kann man sämtliche Widgets interaktiv implementieren. Der InteractiveViewer bietet verschiedene Callback-Funktionen und deckt dabei sämtliche mögliche Gestures ab. ``` @override Widget build(BuildContext context) { return InteractiveViewer(child: Image.asset('assets/images/mona_lisa.jpg')); } ``` ### Persistieren von Daten mithilfe von SharedPreferences SharedPreferences ist eine einfache Möglichkeit, Daten lokal auf dem Gerät zu speichern. Hier wird zunächst eine Instanz von SharedPreferences erstellt: ``` final prefs = await SharedPreferences.getInstance(); ``` Anschließend können Daten (in unserem Fall der Search Query der Wetter-Suche) gespeichert werden: ``` await _prefs.setString( 'LOCATION_QUERY', locationQuery, ); ``` Ähnlich einfach gestaltet sich das Auslesen von Daten: ``` String _locationQuery = ''; var sharedPreferencesLocation = _prefs.getString('LOCATION_QUERY'); if (sharedPreferencesLocation == null) { _locationQuery = ''; } else { _locationQuery = sharedPreferencesLocation; } ``` ## Vorteile von Flutter - Nahezu native Leistung: Flutter verwendet die Programmiersprache Dart und kompiliert in Maschinencode. Host-Geräte verstehen diesen Code, was eine schnelle und effektive Leistung gewährleistet. - Schnelles, konsistentes und anpassbares Rendering: Anstatt sich auf plattformspezifische Rendering-Tools zu verlassen, verwendet Flutter die Open-Source-Skia-Grafikbibliothek von Google, um die Benutzeroberfläche zu rendern. Dies bietet Benutzern konsistente visuelle Darstellungen, unabhängig davon, welche Plattform sie für den Zugriff auf eine Anwendung verwenden. - Entwicklerfreundliche Tools: Google hat Flutter mit Schwerpunkt auf Benutzerfreundlichkeit entwickelt. Mit Tools wie Hot Reload können Entwickler eine Vorschau anzeigen, wie Codeänderungen aussehen werden, ohne den Status zu verlieren. Andere Tools wie der Widget Inspector erleichtern die Visualisierung und Lösung von Problemen mit UI-Layouts. - Starke Typsicherheit: Dart ist eine stark typisierte Programmiersprache, die Entwicklern hilft, Fehler zu vermeiden und die Codequalität zu verbessern. [flutter_aws](https://aws.amazon.com/de/what-is/flutter/) ## Nachteile von Flutter - große App-Größe: vor allem im Vergleich zu nativer App-Entwicklung - begrenzte Bibliotheken und Pakete: war stellt das Framework selbst ständig neue Plug-ins und Pakete bereit, doch weil es noch relativ neu ist, gibt es nur wenige Bibliotheken von Drittanbietern. Das ist ein Unterschied zu etablierten Frameworks wie beispielsweise React Native. [nachteile_flutter](https://www.yuhiro.de/vorteile-und-nachteile-von-flutter/) ## Fazit Flutter ist ein leistungsstarkes und vielseitiges Framework zur Entwicklung plattformübergreifender Anwendungen. Es bietet eine hohe Geschwindigkeit und Effizienz bei der Entwicklung durch seine einheitliche Codebasis und die umfangreiche Sammlung an vorgefertigten Widgets. Die Möglichkeit, sowohl mobile als auch Web- und Desktop-Anwendungen mit demselben Code zu erstellen, macht Flutter zu einer gute Option für viele Entwickler. Allerdings bringt Flutter auch ein paar Nachteile mit sich. Die größere App-Größe, die begrenzte Anzahl an Bibliotheken und Paketen im Vergleich zu nativen Frameworks und mögliche Leistungsprobleme bei sehr komplexen Anwendungen sind Aspekte, die bedacht werden müssen. Zudem kann die Integration plattform-spezifischer Funktionen zusätzlichen Aufwand erfordern. ## Quellen [flutter_aws](https://aws.amazon.com/de/what-is/flutter/) [Flutter Documentation](https://docs.flutter.dev/) [Layouts in Flutter](https://docs.flutter.dev/ui/layout) [Difference between stateless and stateful widgets](https://blog.logrocket.com/difference-between-stateless-stateful-widgets-flutter/) [nachteile_flutter](https://www.yuhiro.de/vorteile-und-nachteile-von-flutter/)