Appearance
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.ttf3. 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 aktualisiertWichtige 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:
- Speichern Sie die Datei (
Ctrl + S/Cmd + S) - Die App sollte sofort aktualisiert werden
- Ändern Sie
Colors.greenzuColors.redund 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.dartFehler 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 getZusammenfassung
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.dartDatei 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:
- Erstellen Sie ein neues Flutter-Projekt und analysieren Sie die Struktur
- Modifizieren Sie
main.dart, um eine persönliche Willkommensseite zu erstellen - Fügen Sie ein Bild zu
assets/images/hinzu und zeigen Sie es in der App an (denken Sie daran,pubspec.yamlzu konfigurieren!) - Experimentieren Sie mit Hot Reload: Ändern Sie Farben, Texte und beobachten Sie die sofortige Aktualisierung
Häufige Fehler:
- ❌
pubspec.yamlnach Änderungen nichtflutter pub getausführen - ❌ Dateien im falschen Ordner speichern (alle in
lib/statt Unterordner zu verwenden) - ❌
main.dartlöschen oder umbenennen (App wird nicht starten!) - ❌
BuildContextnicht verstehen (führt zu Fehlern bei Routing & State Management)
