Skip to content

Kapitel 3: Projektstruktur

3.1 Flutter-Projektverzeichnisstruktur

Ein typisches Flutter-Projekt hat folgende Struktur:

mein_projekt/
├── lib/                      # KERN-CODE (Hier programmieren Sie!)
│   ├── main.dart             # Einstiegspunkt der App
│   ├── screens/              # Seiten (z.B. HomeScreen, LoginScreen)
│   ├── widgets/              # Wiederverwendbare Komponenten
│   ├── models/               # Datenmodelle (JSON-Parsing)
│   ├── services/             # Services (API, Datenbank)
│   └── utils/                # Hilfsfunktionen

├── test/                     # Unit- & Widget-Tests
│   └── widget_test.dart

├── assets/                   # Statische Ressourcen
│   ├── images/               # Bilder
│   ├── fonts/                # Schriftarten
│   └── config/               # Konfigurationsdateien

├── pubspec.yaml              # ABHÄNGIGKEITEN & RESSOURCEN (WICHTIG!)
├── pubspec.lock              # Gesperrte Versionen der Abhängigkeiten

├── android/                  # Android-spezifische Dateien (Nur bei Bedarf bearbeiten)
│   ├── app/
│   │   └── src/main/
│   │       └── AndroidManifest.xml  # Android-Berechtigungen
│   ├── build.gradle          # Android-Build-Konfiguration
│   └── ...

├── ios/                      # iOS-spezifische Dateien (Nur bei Bedarf bearbeiten)
│   ├── Runner/
│   │   └── Info.plist       # iOS-Berechtigungen & Konfiguration
│   ├── Podfile               # iOS-Abhängigkeiten
│   └── ...

├── web/                      # Web-spezifische Dateien
│   ├── index.html
│   └── ...

├── linux/                    # Linux-Desktop-Dateien
├── macos/                    # macOS-Desktop-Dateien
├── windows/                  # Windows-Desktop-Dateien

└── build/                    # Build-Output (automatisch generiert)

Wichtigste Dateien für Anfänger

1. lib/main.dart (WICHTIGSTE DATEI)

dart
// Dies ist der EINSTIEGSPUNKT Ihrer App
void main() {
  runApp(MyApp());  // Startet die Flutter-App
}

2. pubspec.yaml (ABHÄNGIGKEITEN & RESSOURCEN)

yaml
name: mein_projekt
description: Eine Flutter-Anwendung

environment:
  sdk: '>=3.0.0 <4.0.0'
  flutter: '>=3.0.0'

dependencies:               # Externe Pakete (Plugins)
  flutter:
    sdk: flutter
  dio: ^5.0.0             # Netzwerkrequest-Bibliothek
  shared_preferences: ^2.2.0  # Lokale Speicherung

dev_dependencies:           # Nur für Entwicklung (Tests, Linting)
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true
  
  assets:                   # Bilder & Ressourcen hier registrieren
    - assets/images/
    - assets/fonts/
  
  fonts:                    # Benutzerdefinierte Schriftarten
    - family: SchöneSchrift
      fonts:
        - asset: assets/fonts/SchoeneSchrift.ttf

3. android/app/src/main/AndroidManifest.xml (Android-Berechtigungen)

xml
<manifest xmlns:android="...">
    <!-- Internet-Berechtigung hinzufügen -->
    <uses-permission android:name="android.permission.INTERNET"/>
    
    <!-- Kamera-Berechtigung -->
    <uses-permission android:name="android.permission.CAMERA"/>
    
    <application
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

4. ios/Runner/Info.plist (iOS-Berechtigungen)

xml
<key>CFBundleURLTypes</key>
<array/>
<key>io.flutter.embedded_views_preview</key>
<true/>
<!-- Kamera-Berechtigung -->
<key>NSCameraUsageDescription</key>
<string>App benötigt Kamerazugriff</string>
<!-- Fotos-Berechtigung -->
<key>NSPhotoLibraryUsageDescription</key>
<string>App benötigt Zugriff auf Fotos</string>

3.2 Dart & Flutter Verbindung

Dart-Syntax in Flutter

Flutter verwendet Dart als Programmiersprache. Hier sind die wichtigsten Dart-Konzepte in Flutter:

1. Variablen & Datentypen

dart
// In Flutter verwenden Sie oft Widget-Typen
Widget meinWidget = Text('Hallo');  // Widget-Typ
const String titel = 'Meine App';   // Konstante (Compile-Zeit)
final int zaehler = 0;              // Final (Laufzeit-Konstante)

2. Funktionen & Arrow-Syntax

dart
// Normale Funktion
Widget buildButton() {
  return ElevatedButton(
    onPressed: () {},
    child: Text('Klick mich'),
  );
}

// Arrow Function (kurz)
Widget buildText() => Text('Kurz und knapp');

// Callback-Funktion (wichtig für Events!)
ElevatedButton(
  onPressed: () {
    print('Button geklickt!');
  },
  child: Text('Klick'),
)

3. Collections (Listen & Maps)

dart
// List (Liste von Widgets)
List<Widget> items = [
  Text('Element 1'),
  Text('Element 2'),
  Text('Element 3'),
];

// Map (Schlüssel-Wert-Paare)
Map<String, dynamic> user = {
  'name': 'Max',
  'alter': 25,
  'istAdmin': false,
};

// In Flutter: Liste von Widgets dynamisch erstellen
Column(
  children: items,  // Liste von Widgets als Children
)

4. Asynchrone Programmierung (Future, async/await)

dart
// In Flutter sehr wichtig für Netzwerkrequests!
Future<String> ladeDaten() async {
  // Simuliere Netzwerkrequest
  await Future.delayed(Duration(seconds: 2));
  return 'Daten geladen';
}

// Verwendung in Flutter
ElevatedButton(
  onPressed: () async {
    String ergebnis = await ladeDaten();
    print(ergebnis);
  },
  child: Text('Daten laden'),
)

5. Klassen & Objekte

dart
// Dart-Klasse
class User {
  final String name;
  final int alter;
  
  User(this.name, this.alter);  // Kurzschreibweise
  
  void vorstellen() {
    print('Hallo, ich bin $name und $alter Jahre alt.');
  }
}

// In Flutter: Widget-Klassen
class MeineSeite extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Ich bin ein Widget!');
  }
}

6. Null Safety

dart
// Nullable Typ (kann null sein)
String? name;  // String oder null

// Late Keyword (wird später initialisiert)
late String beschreibung;

// Assertion Operator (!) - Vorsicht!
String? nullableString;
String nonNullString = nullableString!;  // Wirf Fehler, wenn null!

Flutter-spezifische Dart-Konzepte

1. Widget

dart
// Alles in Flutter ist ein Widget!
// Widget = Bauplan für UI-Elemente

// Einfaches Widget
Text('Hallo')  // Ein Text-Widget

// Zusammengesetztes Widget
Container(
  child: Text('Hallo'),
)

2. BuildContext

dart
// BuildContext = Der Standort eines Widgets im Widget-Baum
// Wird verwendet, um auf übergeordnete Widgets zuzugreifen

Widget build(BuildContext context) {
  // 'context' ist der BuildContext dieses Widgets
  return Scaffold(
    appBar: AppBar(
      title: Text('Titel'),
    ),
  );
}

3.3 main.dart Einstiegsdatei analysieren

Lassen Sie uns eine typische main.dart analysieren:

dart
// 1. Importe
import 'package:flutter/material.dart';  // Material Design Widgets

// 2. Einstiegspunkt (main-Funktion)
void main() {
  // runApp() startet die Flutter-App
  runApp(const MyApp());
}

// 3. Root-Widget (Basis der App)
class MyApp extends StatelessWidget {
  const MyApp({super.key});  // Konstruktor

  @override
  Widget build(BuildContext context) {
    // MaterialApp = Grundgerüst einer Material Design App
    return MaterialApp(
      title: 'Meine Flutter App',  // Titel (für Task-Manager)
      
      // Theme (Aussehen der App)
      theme: ThemeData(
        primarySwatch: Colors.blue,  // Hauptfarbe
      ),
      
      // Startseite
      home: const MyHomePage(),
    );
  }
}

// 4. Startseite (Home Page)
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

// 5. State-Klasse (Zustand der Seite)
class _MyHomePageState extends State<MyHomePage> {
  int _zaehler = 0;  // Zustandsvariable

  // Funktion zum Erhöhen des Zählers
  void _erhoeheZaehler() {
    setState(() {  // WICHTIG: setState() aktualisiert die UI
      _zaehler++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(  // Grundgerüst einer Seite
      appBar: AppBar(
        title: const Text('Startseite'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Sie haben den Button so oft gedrückt:'),
            Text(
              '$_zaehler',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _erhoeheZaehler,  // Event-Handler
        child: const Icon(Icons.add),
      ),
    );
  }
}

Programmablauf:

1. main() wird ausgeführt
2. runApp(MyApp()) startet die App
3. MyApp (StatelessWidget) wird gebaut
4. MaterialApp wird initialisiert
5. MyHomePage (StatefulWidget) wird als Startseite geladen
6. _MyHomePageState wird erstellt
7. build()-Methode wird aufgerufen → UI wird gerendert
8. Bei Button-Klick: _erhoeheZaehler() → setState() → UI aktualisiert

Wichtige Konzepte in main.dart:

  • runApp(): Startet die Flutter-App
  • StatelessWidget: Widget ohne Zustand (statisch)
  • StatefulWidget: Widget mit Zustand (dynamisch)
  • setState(): Aktualisiert die UI bei Zustandsänderung
  • BuildContext: Standort im Widget-Baum
  • MaterialApp: Grundgerüst für Material Design
  • Scaffold: Seitengerüst (AppBar, Body, FAB)

3.4 Praxisbeispiel: main.dart modifizieren

Übung: Eigene einfache Seite erstellen

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Meine erste App',
      theme: ThemeData(
        primarySwatch: Colors.green,  // Farbe ändern
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Willkommen'),
      ),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Icon(Icons.home, size: 100, color: Colors.green),
            SizedBox(height: 20),  // Abstand
            Text(
              'Willkommen zu meiner App!',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 10),
            Text(
              'Dies ist eine einfache Seite.',
              style: TextStyle(fontSize: 16, color: Colors.grey),
            ),
          ],
        ),
      ),
    );
  }
}

Hot Reload testen:

  1. Speichern Sie die Datei (Ctrl + S / Cmd + S)
  2. Die App sollte sofort aktualisiert werden
  3. Ändern Sie Colors.green zu Colors.red und beobachten Sie die Aktualisierung

3.5 Häufige Fehler

Fehler 1: Dart-Syntax & Flutter-Kombination falsch

Fehlerhaft:

dart
// FALSCH: Widget muss ein Widget zurückgeben
Widget buildText() {
  print('Hallo');  // Kein Widget!
}

Richtig:

dart
// RICHTIG: Widget zurückgeben
Widget buildText() {
  return Text('Hallo');  // Gibt Widget zurück
}

Fehler 2: Projektstruktur verwirrend

FALSCHE Struktur:

lib/
├── main.dart
├── page1.dart
├── page2.dart
├── widget1.dart
└── ... (alle Dateien im selben Ordner)

RICHTIGE Struktur:

lib/
├── main.dart
├── screens/
│   ├── home_screen.dart
│   └── profile_screen.dart
├── widgets/
│   ├── custom_button.dart
│   └── custom_card.dart
└── models/
    └── user_model.dart

Fehler 3: pubspec.yaml falsch konfiguriert

Fehlerhaft:

yaml
dependencies:
  dio: ^5.0.0
  shared_preferences: ^2.2.0
  
# Vergessen, Pakete zu installieren!

Richtig:

bash
# Nach Änderungen an pubspec.yaml immer ausführen:
flutter pub get

Zusammenfassung

In diesem Kapitel haben Sie:

  • ✅ Die Flutter-Projektstruktur verstanden
  • ✅ Wichtige Dateien identifiziert (main.dart, pubspec.yaml)
  • ✅ Die Verbindung zwischen Dart und Flutter gelernt
  • ✅ Die main.dart Datei analysiert (Programmablauf)
  • ✅ Ein einfaches Beispiel erstellt und Hot Reload getestet
  • ✅ Häufige Fehler vermieden

Nächstes Kapitel: Wir werden Flutter-Kernkonzepte lernen (Widgets, BuildContext, Hot Reload, Rendering).


Übungsaufgaben:

  1. Erstellen Sie ein neues Flutter-Projekt und analysieren Sie die Struktur
  2. Modifizieren Sie main.dart, um eine persönliche Willkommensseite zu erstellen
  3. Fügen Sie ein Bild zu assets/images/ hinzu und zeigen Sie es in der App an (denken Sie daran, pubspec.yaml zu konfigurieren!)
  4. Experimentieren Sie mit Hot Reload: Ändern Sie Farben, Texte und beobachten Sie die sofortige Aktualisierung

Häufige Fehler:

  • pubspec.yaml nach Änderungen nicht flutter pub get ausführen
  • ❌ Dateien im falschen Ordner speichern (alle in lib/ statt Unterordner zu verwenden)
  • main.dart löschen oder umbenennen (App wird nicht starten!)
  • BuildContext nicht verstehen (führt zu Fehlern bei Routing & State Management)

Frei für alle Anfänger