Flutter-Tutorial: So entwickeln Sie Apps mit dem Google-SDK

Wer eine eigene App programmieren möchte, hat dafür zahlreiche Optionen. Baukästen mit einsatzfertigen App-Komponenten erfreuen sich aufgrund ihrer einfachen Nutzbarkeit großer Beliebtheit, doch auch Frameworks zeichnen sich zunehmend dadurch aus, den Entwicklungsprozess für Nutzer so einfach wie möglich zu gestalten. Einer der modernsten Vertreter ist das von Google entwickelte Software Development Kit (SDK) Flutter. Das quelloffene Framework ermöglicht die Entwicklung hoch performanter Mobile Apps (für iOS und Android) sowie von Web- und Desktopanwendungen in der Google-Sprache Dart.

In unserem Flutter-Tutorial stellen wir Ihnen die wichtigsten Schritte zum Einstieg in die Google-SDK vor.

Flutter lernen: Das sind die Voraussetzungen

Wer das Programmieren mit Flutter lernen möchte, benötigt nicht zwingend Vorwissen in Sachen App- und Webentwicklung. Auch die bereits genannte Google-Sprache Dart kann Ihnen prinzipiell noch gänzlich fremd sein. Falls Sie mit objektorientiertem Code und grundlegenden Programmierkonzepten wie Variablen, Schleifen und Bedingungen vertraut sind, sind Sie bereits gut für die Arbeit mit dem Framework gerüstet.

In diesem Flutter-Tutorial wollen wir einen ersten Blick auf die Entwicklung mit dem Software-Development-Kit werfen und zu diesem Zweck eine einfache App schreiben, die nach zufälligem Muster Wörter kombiniert und diese Kombinationen im Anschluss präsentiert. Hierfür benötigen Sie die Basis-Werkzeuge für die Programmierung mit Flutter: Das Flutter-SDK und einen Editor. Erstgenanntes ist für Windows, macOS und Linux verfügbar – das jeweilige Installationspaket können Sie direkt über die offizielle Flutter-Website herunterladen.

In puncto Editor haben Sie im Prinzip die freie Auswahl. Für eine optimale User-Experience mit automatischer Code-Vervollständigung, Syntaxhervorhebung sowie Unterstützung bei Debugging und der Bearbeitung von Widgets empfiehlt Google aber die Nutzung eines Code-Editors für den der Großkonzern auch ein offizielles Flutter-Plugin anbietet: In unserem Flutter-Tutorial nutzen wir aus diesem Grund Android Studio. Nach der Installation dieser für die Android-App-Entwicklung optimierten Entwicklungsumgebung richten Sie das Flutter-Plugin folgendermaßen ein:

  1. Rufen Sie den Menüpunkt „File“ auf.
  2. Klicken Sie auf „Settings“ und wählen Sie danach die Rubrik „Plugins“ aus.
  3. Tippen Sie „Dart“ in die Suchzeile ein und klicken Sie beim gleichnamigen vorgeschlagenen Ergebnis auf den „Install“-Button, um zunächst die Erweiterung für die erforderliche Programmiersprache Dart zu installieren.
  4. Bestätigen Sie die Nutzung der Third-Party-Erweiterung via „Accept“.
  5. Wiederholen Sie den Vorgang für den Suchbegriff „Flutter“ und drücken Sie nach erfolgreicher Installation auf „Restart IDE“, um die Änderungen zu übernehmen.
Hinweis

Als Alternative zu Android Studio schlägt Google die Verwendung von GNU Emacs, Visual Studio Code und IntelliJ IDEA vor – Anwendungen, für die es ebenfalls ein offizielles Flutter-Plugin gibt.

Schritt 1: Die erste eigene Flutter-App erstellen

Sobald Sie Flutter und die gewünschte Entwicklungsumgebung (bzw. den Editor) installiert haben, können Sie Ihre erste Flutter-Anwendung kreieren. Wie bereits erwähnt verwenden wir in diesem Flutter-Tutorial Android Studio, weshalb wir die IDE nun zu diesem Zweck starten. Über das Menü „File“ wählen Sie im ersten Schritt die Punkte „New“ und anschließend „New Flutter Project“ aus, um ein neues Projekt auf Basis des App-Frameworks zu starten.

Wählen Sie „Flutter Application“ als gewünschten Projekttyp aus und drücken Sie auf „Next“. Im Konfigurationsmenü definieren Sie nun einen Arbeitstitel und den lokalen Speicherort für Ihre Anwendung. Optional können Sie auch eine Beschreibung des Projekts hinzufügen. In der Zeile „Flutter SDK path“ geben Sie den Pfad zum installierten Flutter-Framework an.

Klicken Sie zum Abschluss auf „Finish“, damit die neue Flutter-App erstellt wird. In die Datei main.dart, die grundlegende Arbeitsdatei eines Projekts sowie dieses Flutter-Tutorials, fügen Sie nun folgenden Code ein, um die App eine einfache „Hello World“-Nachricht präsentieren zu lassen (bereits vorhandenen Code in der main.dart-Datei können Sie löschen):

// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return MaterialApp(
			title: 'Welcome to Flutter',
			home: Scaffold(
				appBar: AppBar(
					title: Text('Welcome to Flutter'),
				),
				body: Center(
					child: Text('Hello World'),
				),
			),
		);
	  }
}

Sobald Sie das Snippet eingefügt haben, können Sie sich diese erste Version Ihrer eigenen App präsentieren lassen. In Android Studio wählen Sie hierfür die jeweilige virtuelle Maschine aus (unter „Flutter Device Selection“) und drücken anschließend auf den Abspiel-Button („Run main.dart“):

Hinweis

Für die Vorschau einer App in Android Studio muss ein Image der gewünschten Zielplattform installiert sein. Andernfalls können Sie unter „Flutter Device Selection“ kein virtuelles Testgerät für den Test der App auswählen. Zum Hinzufügen wählen Sie die Menüpunkte „Tools“ und „AVD Manager“ aus. Anschließend drücken Sie auf „Create Virtual Device“ und installieren das virtuelle Gerät Ihrer Wahl. Eine ausführliche Anleitung zum Erstellen und Verwalten virtueller Geräte in Android Studio finden Sie im Android-Developer-Forum.

Der erste Start bzw. das Debugging der App wird einige Zeit in Anspruch nehmen – Sie müssen sich also ein wenig gedulden, bevor Sie die Willkommensnachricht auf dem Bildschirm Ihrer Testumgebung sehen.

Schritt 2: Ein externes Paket einbinden

Nachdem wir im ersten Schritt des Flutter-Tutorials eine erste einfache App zum Laufen gebracht haben, soll diese nun um ein externes Paket erweitert werden. Genauer gesagt wollen wir nun das für unser Projektziel – eine App, die Wörter nach einem zufälligen Muster miteinander kombiniert – erforderliche Wörterpaket einbinden. Exemplarisch nutzen wir das Open-Source-Paket „english_words“ (MIT-Lizenz), das Sie wie viele andere quelloffene Pakete auf der Plattform pub.dev finden. Das Modul enthält die über 5000 gängigsten englischen Wörter, weshalb es optimal für die Zwecke dieses Flutter-Tutorials geeignet ist.

Für das Management von Paketen und Abhängigkeiten nutzen Flutter-Apps die Datei pubspec.yaml. Rufen Sie diese Datei auf und fügen der Liste der Abhängigkeiten einen Eintrag für das Sprachpaket (auf aktuelle Version achten; hier: 3.1.5) hinzu:

dependencies:
	flutter:
		sdk: flutter
	cupertino_icons: ^0.1.2
english_words: ^3.1.5

Anschließend führen Sie den Befehl „flutter pub get“ aus. Android Studio hat hierfür sogar direkt eine Schaltfläche mit dem Namen „Pub get“ parat.

Wechseln Sie zurück zur Haupt-Arbeitsdatei main.dart und importieren Sie dort das Sprachpaket:

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

Zudem fügen Sie im Code der App die folgende Zeile hinzu:

final wordPair = WordPair.random();

Zum Abschluss ersetzen Sie den child-Eintrag, der für die Ausgabe des Textes „Hello World“ sorgt durch folgenden Eintrag:

child: Text(wordPair.asPascalCase),

Mit jeder Ausführung dieses neuen, aktuellen App-Codes erhalten Sie nun ein zufällig generiertes Paar englischer Wörter.

Schritt 3: Ein zustandsbehaftetes Widget hinzufügen

Zustandslose Widgets (Stateless Widgets), wie bisher in diesem Google-Flutter-Tutorial genutzt, sind unveränderlich. Während der Laufzeit einer App können sie ihren Status nicht ändern, weshalb sich diese Art von Widgets nicht umschreiben lässt, während die Anwendung ausgeführt wird. Zustandsbehaftete Widgets (auch Stateful Widgets) können ihren Status hingegen auch während der App-Laufzeit verändern, sodass dieser nicht bereits mit der Ausführung feststehen muss. Möchten Sie bestimmten Elementen Ihrer Flutter-App also Interaktivität verleihen, benötigen Sie Stateful Widgets.

Hinweis

Widgets sind in Flutter immer entweder zustandslos oder zustandsbehaftet. Typische Beispiele für zustandslose Komponenten sind Icons, Buttons oder Text-Bausteine. Typische Beispiele für einfache zustandsbehaftete Widgets sind Checkboxen, Formulare oder Schieberegler.

Auch unsere Beispiel-App soll an dieser Stelle ein interaktives Widget erhalten. Für die Implementierung sind mindestens zwei Klassen erforderlich: Eine StatefulWidget-Klasse, die ihrerseits wiederum eine Instanz der State-Klasse generiert.

Zu Beginn erstellen wir eine minimalistische State-Klasse namens „RandomWordsState“, indem wir folgenden Code an das Ende der main.dart einfügen:

class RandomWordsState extends State<randomwords> {</randomwords>
	// TODO Add build() method
}

Die generische State-Klasse wird in diesem Fall explizit für die Nutzung mit dem Widget „RandomWords“ zugewiesen. Das Stateful Widget selbst wird im nächsten Schritt durch folgenden Input in die main.dart-Datei geschrieben (im Code: vor der Klasse „RandomWordsState“):

class RandomWords extends StatefulWidget {
	@override
	RandomWordsState createState() => RandomWordsState();
}

Führen Sie diesen neuen App-Code aus, liefert Flutter Ihnen den Hinweis, dass aktuell noch keine build()-Funktion für „RandomWordsState“ definiert ist.

Im eingefügten Snippet der State-Klasse befindet sich an der entscheidenden Stelle noch der Platzhalter-Kommentar „//TODO Add build() method“, der nun durch den Code für die Build()-Funktion ersetzt wird:

class RandomWordsState extends State<randomwords> {</randomwords>
	@override
	Widget build(BuildContext context) {
		final wordPair = WordPair.random();
		return Text(wordPair.asPascalCase);
	}
}

Zuletzt entfernen Sie die Zeile „final wordPair = WordPair.random();“ aus der MyApp-Klasse und ersetzen den Child-Eintrag „child: Text(wordPair.asPascalCase),“ durch „child: RandomWords(),“.

Führen Sie diesen neuen Code nun aus, sollte das virtuelle Testgerät wie zuvor ein Wortpaar ausspielen – nun allerdings auf Basis eines zustandsbehafteten Widgets, das potenziell auch eine Interaktion der zugreifenden Nutzer ermöglicht.

Schritt 4: Eine endlos scrollbare Listenansicht erstellen

Um ein erstes Beispiel für ein interaktives Flutter-Widget zu liefern, soll unsere App im letzten Teil dieses Google-Flutter-Tutorials noch etwas erweitert werden: Genauer gesagt soll die „RandomWordsState“-Klasse dahingehend angepasst werden, dass sie nicht mehr nur einzelne Wortpaare, sondern eine endlose Liste mit Wortpaaren präsentiert, durch die der Nutzer scrollen kann. Zudem sollen bereits vorgeschlagene Wortpaare gespeichert (um doppelte Einträge zu vermeiden) und die Schriftgröße der Ergebnisse vergrößert werden.

Beginnen Sie mit den beiden zuletzt genannten Punkten (Speicherung der präsentierten Ergebnisse und Font-Anpassung), indem Sie eine _suggestions-Liste und eine _biggerFont-Variable einbinden:

class RandomWordsState extends State<randomwords> {</randomwords>
	final _suggestions = <wordpair>[];</wordpair>
	final _biggerFont = const TextStyle(fontSize: 18.0);
}

Im Anschluss fügen Sie – ebenfalls in die „RandomWordsState“-Klasse die passende _buildSuggestions()-Funktion ein:

Widget _buildSuggestions() {
	return ListView.builder(
		padding: const EdgeInsets.all(16.0),
		itemBuilder: (context, i) {
			if (i.isOdd) return Divider();
			final index = i ~/ 2;
			if (index >= _suggestions.length) {
			_suggestions.addAll(generateWordPairs().take(10));
			}
			return _buildRow(_suggestions[index]);
		});
}

Die aufgezeigte Funktion erweitert die App um gleich mehrere Eigenschaften: Unter anderem wird die Auflistung der Wortpaare (List.View) integriert, die zudem durch eine Ein-Pixel-Trennlinie (Divider) übersichtlicher gemacht wird. Zudem ist definiert, dass weitere zehn Vorschläge geliefert werden (Zeile: _suggestions.addAll), sobald der Nutzer an das Ende der aktuell präsentierten Liste gelangt ist.

Elementarer Bestandteil des erweiterten Widgets ist außerdem die Funktion _buildRow(), die einmal pro Wortpaar aufgerufen wird und die Paare als ListTitle präsentiert. Diese Funktion implementieren wir daher gleich im nächsten Schritt:

Widget _buildRow(WordPair pair) {
	return ListTile(
		title: Text(
			pair.asPascalCase,
			style: _biggerFont,
		),
	);
}

Die build()-Methode, die wir bei der Generierung des zustandsbehafteten Widgets (Schritt 3) implementiert haben, muss nun noch angewiesen werden, die Funktion buildSuggestions() zu verwenden. Der bisherige Inhalt der Methode ist daher durch folgenden Code auszutauschen:

@override
Widget build(BuildContext context) {
	return Scaffold(
		appBar: AppBar(
			title: Text('Word Generator'),
		),
		body: _buildSuggestions(),
	);
}

Zuletzt aktualisieren Sie die build()-Methode auch in der MyApp-Klasse, indem Sie den Title ändern und im Home-Eintrag definieren, dass es sich um ein RandomWords-Widget handelt:

title: 'Word Generator',
home: RandomWords(),

Führen Sie den Code nun erneut aus, läuft die App unter dem neuen Titelnamen „Word Generator“. Zudem wird gleich eine ganze Auflistung von Wortkombinationen präsentiert und per Scrollen können Sie weitere Ergebnisse anzeigen lassen.

Flutter-Tutorial: Zusammenfassung

Im Rahmen des vorangegangenen Google-Flutter-Tutorials haben Sie die wichtigsten Grundlagen für die Arbeit mit Flutter gelernt und konnten Sie in einer einfachen Beispiel-App anwenden. Natürlich können Sie Ihre individuellen Flutter-Anwendungen noch deutlich detaillierter und umfangreicher entwickeln. Auch das Design können Sie individuell gestalten, wenn Sie sich erst einmal intensiver mit dem Framework auseinandergesetzt haben.

Abschließend präsentieren wir nun noch einmal den kompletten Code der entwickelten Beispiel-App für Android in der main.dart-Datei:

import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return MaterialApp(
			title: 'Word Generator',
			home: RandomWords(),
		);
	}
}
class RandomWords extends StatefulWidget {
	@override
	RandomWordsState createState() => RandomWordsState();
}
class RandomWordsState extends State<randomwords> {</randomwords>
	final _suggestions = <wordpair>[];</wordpair>
	final _biggerFont = const TextStyle(fontSize: 18.0);
	@override
	Widget build(BuildContext context) {
		return Scaffold(
			appBar: AppBar(
				title: Text('Word Generator'),
			),
			body: _buildSuggestions(),
		);
}
Widget _buildSuggestions() {
		return ListView.builder(
			padding: const EdgeInsets.all(16.0),
			itemBuilder: (context, i) {
				if (i.isOdd) return Divider();
				final index = i ~/ 2;
				if (index >= _suggestions.length) {
				_suggestions.addAll(generateWordPairs().take(10));
				}
				return _buildRow(_suggestions[index]);
			});
}
Widget _buildRow(WordPair pair) {
		return ListTile(
			title: Text(
				pair.asPascalCase,
				style: _biggerFont,
			),
		);
	}
}