Skip to content

Kapitel 17: Fortgeschrittene Tipps

17.1 Flutter Code-Normen

Namenskonventionen

ElementKonventionBeispiel
KlassenamenPascalCaseMyWidget, HomePage
FunktionsnamencamelCasebuildWidget(), loadData()
VariablenamencamelCaseuserName, isLoading
KonstantencamelCase oder SCREAMING_SNAKE_CASEPI, defaultTimeout
Dateinamensnake_casehome_page.dart, user_model.dart
Paketnamenlowercase_with_underscoresshared_preferences, flutter_launcher_icons

Code-Formatierung

analysis_options.yaml konfigurieren:

yaml
include: package:flutter_lints/flutter.yaml

linter_rules:
  - avoid_print  # print() in Produktion vermeiden
  - prefer_const_constructors  # const Konstruktoren bevorzugen
  - unnecessary_null_comparison  # Unnötige Null-Prüfung
  - always_use_package_imports  # Paket-Importe verwenden

Code-Organisation

Schlecht (alles in einer Datei):

dart
// main.dart - ZU VIELE VERANTWORTLICHKEITEN!
class MyApp extends StatelessWidget { ... }
class HomePage extends StatefulWidget { ... }
class LoginPage extends StatefulWidget { ... }
class ApiService { ... }

Gut (Aufteilung in mehrere Dateien):

lib/
├── main.dart
├── pages/
│   ├── home_page.dart
│   └── login_page.dart
├── widgets/
│   ├── custom_button.dart
│   └── custom_card.dart
├── services/
│   └── api_service.dart
└── models/
    └── user_model.dart

17.2 Widget-Kapselung (Code-Wiederverwendbarkeit)

Warum Widgets kapseln?

Vorteile:

  • ✅ Code-Wiederverwendbarkeit
  • ✅ Bessere Lesbarkeit
  • ✅ Leichtere Wartbarkeit
  • ✅ Einheitliches Design

Beispiel: Benutzerdefiniertes Button-Widget

Schlecht (Code-Duplizierung):

dart
// Überall im Code wiederholt
ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.blue,
    padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8),
    ),
  ),
  child: const Text('Button'),
)

Gut (Widget kapseln):

dart
// widgets/custom_button.dart
import 'package:flutter/material.dart';

class CustomButton extends StatelessWidget {
  final String text;
  final VoidCallback? onPressed;
  final Color? color;
  
  const CustomButton({
    super.key,
    required this.text,
    this.onPressed,
    this.color,
  });
  
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(
        backgroundColor: color ?? Colors.blue,
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(8),
        ),
      ),
      child: Text(text),
    );
  }
}

// Verwendung:
CustomButton(
  text: 'Speichern',
  onPressed: () {
    print('Speichern geklickt');
  },
)

Beispiel: Benutzerdefiniertes Card-Widget

dart
// widgets/custom_card.dart
import 'package:flutter/material.dart';

class CustomCard extends StatelessWidget {
  final Widget child;
  final EdgeInsetsGeometry? padding;
  final VoidCallback? onTap;
  
  const CustomCard({
    super.key,
    required this.child,
    this.padding,
    this.onTap,
  });
  
  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 4,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12),
      ),
      child: InkWell(
        onTap: onTap,
        child: Padding(
          padding: padding ?? const EdgeInsets.all(16),
          child: child,
        ),
      ),
    );
  }
}

// Verwendung:
CustomCard(
  onTap: () {
    print('Card geklickt');
  },
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: const <Widget>[
      Text('Titel', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
      SizedBox(height: 8),
      Text('Beschreibung...'),
    ],
  ),
)

17.3 Performance-Optimierung (Grundlagen)

1. const Konstruktoren verwenden

Schlecht:

dart
Text('Hallo')  // Jedes Mal neu erstellt

Gut:

dart
const Text('Hallo')  // Einmal erstellt, wiederverwendet

2. ListView.builder statt ListView.children verwenden

Schlecht (alle Elemente werden auf einmal erstellt):

dart
ListView(
  children: List.generate(1000, (index) => ListTile(title: Text('Element $index'))),
)

Gut (nur sichtbare Elemente werden erstellt):

dart
ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) => ListTile(title: Text('Element $index')),
)

3. Bilder cachen (cached_network_image)

Installation:

yaml
dependencies:
  cached_network_image: ^3.3.0

Verwendung:

dart
CachedNetworkImage(
  imageUrl: 'https://example.com/bild.jpg',
  placeholder: (context, url) => const CircularProgressIndicator(),
  errorWidget: (context, url, error) => const Icon(Icons.error),
)

4. setState() sparsam verwenden

Schlecht (gesamte Seite wird neu gebaut):

dart
void _erhoehen() {
  setState(() {
    _zaehler++;
    _aktualisiereText();  // Unnötig, da es nicht die UI beeinflusst
  });
}

Gut (nur notwendige Teile aktualisieren):

dart
void _erhoehen() {
  setState(() {
    _zaehler++;
  });
}

void _aktualisiereText() {
  // Logik, die kein setState() benötigt
}

5. AnimatedBuilder oder ValueListenableBuilder verwenden

Für komplexe Animationen/Zustandsänderungen:

dart
ValueListenableBuilder<int>(
  valueListenable: _zaehler,
  builder: (context, wert, child) {
    return Text('$wert');
  },
)

17.4 Häufige Drittanbieter-Plugins (nach Anwendungsfall)

Netzwerk

  • dio: ^5.4.0 - Leistungsstarke Netzwerk-Bibliothek
  • http: ^1.1.0 - Einfache HTTP-Anfragen

Lokale Speicherung

  • shared_preferences: ^2.2.0 - Key-Value-Speicherung
  • sqflite: ^2.3.0 - Lokale Datenbank
  • hive: ^2.2.3 - NoSQL, schnelle Leistung

UI-Komponenten

  • flutter_screenutil: ^5.9.0 - Responsive Design
  • flutter_swiper: ^1.1.6 - Bild-Karussell
  • percent_indicator: ^4.2.3 - Fortschrittsanzeige

Zustandsverwaltung

  • provider: ^6.1.1 - Empfohlen (einfach)
  • get: ^4.6.5 - Einfach, beliebt
  • flutter_bloc: ^8.1.2 - Für große Projekte

Andere

  • image_picker: ^1.0.4 - Bilder aus Kamera/Galerie auswählen
  • url_launcher: ^6.1.11 - URLs öffnen (Browser, Telefon, E-Mail)
  • package_info_plus: ^4.2.0 - App-Informationen abrufen (Version, Name)

17.5 Flutter-Versionsaktualisierung & Kompatibilitätsbehandlung

Flutter-Version aktualisieren

bash
# Aktuelle Version überprüfen
flutter --version

# Auf stable Version aktualisieren
flutter upgrade

# Auf bestimmte Version wechseln
flutter version v3.16.0

pubspec.yaml nach Aktualisierung anpassen

yaml
environment:
  sdk: '>=3.0.0 <4.0.0'  # SDK-Version anpassen
  flutter: '>=3.0.0'        # Flutter-Version anpassen

dependencies:
  flutter:
    sdk: flutter
  dio: ^5.4.0  # Bibliotheksversionen überprüfen
bash
# Abhängigkeiten aktualisieren
flutter pub get

Häufige Kompatibilitätsprobleme

Problem: Nach der Aktualisierung treten Fehler auf.

Lösungen:

  1. flutter clean ausführen
  2. flutter pub get ausführen
  3. flutter upgrade --force erzwingt Aktualisierung
  4. pubspec.yaml überprüfen (Versionen anpassen)

Zusammenfassung

In diesem Kapitel haben Sie:

  • ✅ Flutter Code-Normen gelernt
  • ✅ Widget-Kapselung für Code-Wiederverwendbarkeit implementiert
  • ✅ Performance-Optimierung (const, ListView.builder, Bild-Caching) gelernt
  • ✅ Häufige Drittanbieter-Plugins kennengelernt
  • ✅ Flutter-Versionsaktualisierung und Kompatibilitätsbehandlung gelernt

Nächstes Kapitel: Wir werden Flutter-Häufige Interviewfragen lernen.


Übungsaufgaben:

  1. Kapseln Sie ein benutzerdefiniertes Widget (z.B. CustomAppBar)
  2. Optimieren Sie eine Liste mit 1000 Elementen (verwenden Sie ListView.builder)
  3. Fügen Sie Bild-Caching mit cached_network_image hinzu
  4. Aktualisieren Sie Ihr Projekt auf die neueste Flutter-Version

Häufige Fehler:

  • ❌ Widgets nicht kapseln → Code-Duplizierung
  • ListView ohne builder für große Datenmengen verwenden → Performance-Probleme
  • setState() zu häufig aufrufen → Unnötige Rebuilds
  • ❌ Flutter-Version nicht aktualisieren → Sicherheitslücken, fehlende Funktionen

Frei für alle Anfänger