Skip to content

Anhang: Flutter Kernwissen

1. Kern-Widgets (nach Verwendungshäufigkeit, mit Beispielen)

Häufig verwendete Widgets

WidgetVerwendungBeispiel
TextTextanzeigeText('Hallo')
ImageBilderImage.network('url')
ElevatedButtonButtonElevatedButton(onPressed: () {}, child: Text('Klick'))
TextFieldEingabefeldTextField(controller: _controller)
ContainerContainerContainer(padding: EdgeInsets.all(16))
RowHorizontales LayoutRow(children: [Widget1(), Widget2()])
ColumnVertikales LayoutColumn(children: [Widget1(), Widget2()])
StackStapel-LayoutStack(children: [Widget1(), Widget2()])
ListViewListeListView.builder(itemCount: 10, itemBuilder: (context, index) {...})
GridViewGridGridView.count(crossAxisCount: 2, children: [...])
CardKarteCard(child: ListTile(title: Text('Titel')))
ScaffoldSeitengerüstScaffold(appBar: AppBar(title: Text('Titel')))
AppBarObere LeisteAppBar(title: Text('Titel'), actions: [IconButton(...)])
IconIconIcon(Icons.home)
IconButtonIcon-ButtonIconButton(icon: Icon(Icons.home), onPressed: () {})
CircleAvatarRundes BildCircleAvatar(backgroundImage: NetworkImage('url'))
DividerTrennlinieDivider()
SizedBoxGrößen-BoxSizedBox(height: 20)
SpacerAbstand füllenSpacer()
ExpandedPlatz füllenExpanded(child: Text('Text'))
FlexibleFlexibler PlatzFlexible(child: Text('Text'))
PositionedPositionierungPositioned(top: 10, left: 10, child: Widget())
RefreshIndicatorPull-to-RefreshRefreshIndicator(onRefresh: _aktualisieren, child: ListView(...))
SingleChildScrollViewScrollbares WidgetSingleChildScrollView(child: Column(...))
AlertDialogDialogAlertDialog(title: Text('Titel'), content: Text('Inhalt'))
showModalBottomSheetBottom-SheetshowModalBottomSheet(context: context, builder: (context) => Widget())

2. Layout-Widgets Verwendungsfälle (Row, Column, Stack, etc.)

Row (Horizontales Layout)

Verwendungsfälle:

  • ✅ Buttons nebeneinander
  • ✅ Icon + Text nebeneinander
  • ✅ Bild + Beschreibung nebeneinander

Beispiel:

dart
Row(
  mainAxisAlignment: MainAxisAlignment.spaceAround,
  children: <Widget>[
    Icon(Icons.home),
    Text('Startseite'),
    ElevatedButton(onPressed: () {}, child: Text('Go')),
  ],
)

Column (Vertikales Layout)

Verwendungsfälle:

  • ✅ Formularfelder untereinander
  • ✅ Listenelemente
  • ✅ Seiteninhalt (von oben nach unten)

Beispiel:

dart
Column(
  mainAxisAlignment: MainAxisAlignment.center,
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: <Widget>[
    Text('Zeile 1'),
    Text('Zeile 2'),
    ElevatedButton(onPressed: () {}, child: Text('Button')),
  ],
)

Stack (Stapel-Layout)

Verwendungsfälle:

  • ✅ Bild mit Text-Overlay
  • ✅ Badge auf Icon
  • ✅ Floating Action Button positionieren

Beispiel:

dart
Stack(
  children: <Widget>[
    Container(width: 300, height: 300, color: Colors.grey.shade200),
    Positioned(
      top: 10,
      left: 10,
      child: Icon(Icons.home, size: 30),
    ),
  ],
)

ListView (Liste)

Verwendungsfälle:

  • ✅ Neuigkeiten-Liste
  • ✅ Kontaktliste
  • ✅ Produktliste

Beispiel:

dart
ListView.builder(
  itemCount: 10,
  itemBuilder: (context, index) {
    return ListTile(
      leading: Icon(Icons.person),
      title: Text('Element $index'),
    );
  },
)

GridView (Grid)

Verwendungsfälle:

  • ✅ Produkt-Grid
  • ✅ Bild-Galerie
  • ✅ Kategorie-Grid

Beispiel:

dart
GridView.count(
  crossAxisCount: 2,
  children: <Widget>[
    Card(child: Text('Element 1')),
    Card(child: Text('Element 2')),
  ],
)

3. State Management Methoden (setState, Provider, GetX)

setState() (Einfachste Methode)

Verwendungsfall:

  • ✅ Einfache Zustände (lokaler Zustand)
  • ✅ Wenige Widgets betroffen
  • ✅ Keine komplexe Zustandsverwaltung notwendig

Beispiel:

dart
class CounterPage extends StatefulWidget {
  const CounterPage({super.key});

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _zaehler = 0;
  
  void _erhoehen() {
    setState(() {
      _zaehler++;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('$_zaehler', style: const TextStyle(fontSize: 48)),
            ElevatedButton(
              onPressed: _erhoehen,
              child: const Text('Erhöhen'),
            ),
          ],
        ),
      ),
    );
  }
}

Provider (Offiziell empfohlen)

Verwendungsfall:

  • ✅ Cross-Widget Zustandsverwaltung
  • ✅ Mittlere Komplexität
  • ✅ Gute Dokumentation

Beispiel:

Schritt 1: Zustands-Klasse definieren

dart
class CounterProvider extends ChangeNotifier {
  int _zaehler = 0;
  
  int get zaehler => _zaehler;
  
  void erhoehen() {
    _zaehler++;
    notifyListeners();
  }
}

Schritt 2: Zustand bereitstellen

dart
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CounterProvider(),
      child: const MyApp(),
    ),
  );
}

Schritt 3: Zustand verbrauchen

dart
class CounterPage extends StatelessWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Consumer<CounterProvider>(
            builder: (context, provider, child) {
              return Text(
                '${provider.zaehler}',
                style: const TextStyle(fontSize: 48),
              );
            },
          ),
          ElevatedButton(
            onPressed: () {
              Provider.of<CounterProvider>(context, listen: false).erhoehen();
            },
            child: const Text('Erhöhen'),
          ),
        ],
      ),
    );
  }
}

GetX (Einfach & beliebt)

Verwendungsfall:

  • ✅ Schnelle Entwicklung
  • ✅ Wenig Code
  • ✅ Kombiniert Zustandsverwaltung, Routing, Abhängigkeitsinjektion

Beispiel:

Schritt 1: Controller erstellen

dart
class CounterController extends GetxController {
  int zaehler = 0;
  
  void erhoehen() {
    zaehler++;
    update();
  }
}

Schritt 2: Controller verwenden

dart
class CounterPage extends StatelessWidget {
  final controller = Get.put(CounterController());
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: <Widget>[
            GetBuilder<CounterController>(
              builder: (c) => Text('${c.zaehler}'),
            ),
            ElevatedButton(
              onPressed: controller.erhoehen,
              child: const Text('Erhöhen'),
            ),
          ],
        ),
      ),
    );
  }
}

4. Netzwerkrequest & JSON-Parsing Vorlagen (kopieren & verwenden)

GET-Request (Daten abrufen)

Vorlage:

dart
import 'package:dio/dio.dart';

final dio = Dio();

Future<void> ladeDaten() async {
  try {
    final response = await dio.get('https://example.com/api');
    print('Erfolg! Statuscode: ${response.statusCode}');
    print('Daten: ${response.data}');
  } catch (e) {
    print('Fehler: $e');
  }
}

POST-Request (Daten senden)

Vorlage:

dart
import 'package:dio/dio.dart';

final dio = Dio();

Future<void> sendeDaten() async {
  try {
    final response = await dio.post(
      'https://example.com/api',
      data: {
        'name': 'Max',
        'alter': 25,
      },
    );
    print('Erfolg! Statuscode: ${response.statusCode}');
    print('Antwort: ${response.data}');
  } catch (e) {
    print('Fehler: $e');
  }
}

JSON-Parsing (Manuell)

Vorlage:

dart
// Angenommen, API gibt JSON zurück:
// {
//   "id": 1,
//   "title": "BeispielTitel",
//   "body": "BeispielInhalt"
// }

final response = await dio.get('https://example.com/api');

// Manuelle Parsing
final data = response.data;
final titel = data['title'];
final inhalt = data['body'];

print('Titel: $titel');
print('Inhalt: $inhalt');

JSON-Parsing (Automatisch mit json_serializable)

Schritt 1: Abhängigkeiten installieren

yaml
dependencies:
  json_annotation: ^4.8.0

dev_dependencies:
  build_runner: ^2.4.0
  json_serializable: ^6.7.0

Schritt 2: Modellklasse definieren

dart
import 'package:json_annotation/json_annotation.dart';

part 'post_model.g.dart';

@JsonSerializable()
class Post {
  final int id;
  final String title;
  final String body;
  
  Post({
    required this.id,
    required this.title,
    required this.body,
  });
  
  factory Post.fromJson(Map<String, dynamic> json) => _$PostFromJson(json);
  
  Map<String, dynamic> toJson() => _$PostToJson(this);
}

Schritt 3: Code generieren

bash
flutter pub run build_runner build

Schritt 4: Verwenden

dart
final response = await dio.get('https://example.com/api');
final post = Post.fromJson(response.data);
print('Titel: ${post.title}');
print('Inhalt: ${post.body}');

5. Packaging-Konfiguration Vorlagen (Android/iOS, kopieren & verwenden)

Android (APK/AAB erstellen)

Schritt 1: Signierungsschlüssel generieren

bash
keytool -genkey -v -keystore d:\key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

Schritt 2: key.properties konfigurieren

storePassword=ihr_passwort
keyPassword=ihr_passwort
keyAlias=key
storeFile=d:/key.jks

Schritt 3: build.gradle konfigurieren

gradle
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    ...
    
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
    
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

Schritt 4: APK/AAB erstellen

bash
flutter build apk --release
flutter build appbundle --release

iOS (IPA erstellen - nur auf Mac)

Schritt 1: Xcode konfigurieren

  1. Öffnen Sie ios/Runner.xcworkspace in Xcode
  2. Runner → Signing & Capabilities:
    • Team auswählen (Apple ID hinzufügen)
    • Bundle Identifier festlegen (z.B. com.beispiel.meineapp)

Schritt 2: IPA erstellen

  1. Gerät auswählen: "Any iOS Device (arm64)"
  2. Product → Archive
  3. Nach Abschluss: "Distribute App"
  4. "App Store Connect" wählen
  5. Anweisungen folgen

6. Häufige Fehler-Schnellübersicht (schnelle Fehlersuche)

Fehler 1: Layout-Überlauf (Renderflex overflowed)

Fehlermeldung:

A RenderFlex overflowed by 100 pixels on the right.

Lösungen:

  1. Expanded verwenden
dart
Row(
  children: <Widget>[
    Expanded(child: Text('Sehr langer Text der überläuft...')),
    Icon(Icons.more_vert),
  ],
)
  1. SingleChildScrollView verwenden
dart
SingleChildScrollView(
  scrollDirection: Axis.horizontal,
  child: Row(...),
)
  1. Flexible verwenden
dart
Row(
  children: <Widget>[
    Flexible(child: Text('Langer Text...')),
    Icon(Icons.more_vert),
  ],
)

Fehler 2: Zustandsverwaltungsfehler

Fehler: setState() vergessen.

Lösung:

dart
void _erhoehen() {
  setState(() {
    _zaehler++;  // UI wird aktualisiert!
  });
}

Fehler 3: Netzwerkrequest-Fehler

Fehler: await vergessen.

Lösung:

dart
Future<void> ladeDaten() async {
  final response = await dio.get('https://example.com');  // await verwenden!
  print(response.data);
}

Fehler 4: JSON-Parsing fehlgeschlagen

Fehler: JSON-Struktur stimmt nicht mit Dart-Klasse überein.

Lösung:

  1. Überprüfen Sie die JSON-Struktur der API-Antwort
  2. Stellen Sie sicher, dass Ihre Dart-Klasse mit dem JSON übereinstimmt
  3. Verwenden Sie QuickType oder json_serializable

Fehler 5: Packaging fehlgeschlagen

Fehler: Signierungskonfiguration falsch.

Lösung:

  • Stellen Sie sicher, dass android/key.properties existiert
  • Pfad in build.gradle korrekt

7. Häufig verwendete Drittanbieter-Plugins (nach Anwendungsfall)

Netzwerk

  • dio: ^5.4.0 - Leistungsstarke Netzwerk-Bibliothek

Lokale Speicherung

UI-Komponenten

State Management

Andere

Zusammenfassung

In diesem Anhang haben Sie:

  • ✅ Kern-Widgets (nach Verwendungshäufigkeit) gelernt
  • ✅ Layout-Widgets Verwendungsfälle gelernt
  • ✅ State Management Methoden verglichen
  • ✅ Netzwerkrequest & JSON-Parsing Vorlagen erhalten
  • ✅ Packaging-Konfiguration Vorlagen erhalten
  • ✅ Häufige Fehler-Schnellübersicht erhalten
  • ✅ Häufig verwendete Drittanbieter-Plugins kennengelernt

Glückwunsch! Sie haben den Flutter-Anfänger-Kurs abgeschlossen! 🎉


Nächste Schritte:

  1. Üben Sie mit eigenen Projekten
  2. Erkunden Sie fortgeschrittene Themen (Bloc, GetX, Riverpod)
  3. Erstellen Sie eine vollständige App und veröffentlichen Sie sie im App Store / Play Store
  4. Treten Sie der Flutter-Community bei (Stack Overflow, Reddit, Discord)

Viel Erfolg bei Ihrer Flutter-Reise! 🚀

Frei für alle Anfänger