Skip to content

Kapitel 5: Basis-Widgets

5.1 Text-Widget

Grundlegende Verwendung

dart
Text('Hallo Flutter!')  // Einfacher Text

Text-Eigenschaften

dart
Text(
  'Flutter Lernen',
  style: TextStyle(
    fontSize: 24,              // Schriftgröße
    fontWeight: FontWeight.bold, // Fettschrift
    color: Colors.blue,        // Textfarbe
    fontStyle: FontStyle.italic, // Kursiv
    letterSpacing: 2.0,        // Buchstabenabstand
    wordSpacing: 4.0,          // Wortabstand
    height: 1.5,               // Zeilenhöhe
    decoration: TextDecoration.underline, // Unterstreichung
  ),
  textAlign: TextAlign.center,  // Ausrichtung
  maxLines: 2,                 // Maximale Zeilen
  overflow: TextOverflow.ellipsis, // Überlauf (...)
)

RichText (Mehrfachformatierung)

dart
RichText(
  text: TextSpan(
    text: 'Hallo ',
    style: TextStyle(color: Colors.black, fontSize: 20),
    children: <TextSpan>[
      TextSpan(
        text: 'Flutter',
        style: TextStyle(
          color: Colors.blue,
          fontWeight: FontWeight.bold,
        ),
      ),
      TextSpan(text: '!'),
    ],
  ),
)

5.2 Image-Widget

Bild von URL laden

dart
// Netzwerkbild
Image.network(
  'https://example.com/bild.jpg',
  width: 200,
  height: 200,
  fit: BoxFit.cover,  // Skalierungsmodus
)

BoxFit-Optionen:

  • BoxFit.fill: Streckt Bild, um Container zu füllen
  • BoxFit.contain: Skaliert, um komplett sichtbar zu sein
  • BoxFit.cover: Deckt gesamten Container ab (beschnitten)
  • BoxFit.fitWidth: Passt Breite an
  • BoxFit.fitHeight: Passt Höhe an
  • BoxFit.none: Keine Skalierung

Lokales Bild (Assets)

Schritt 1: Bild zu assets/images/ hinzufügen

Schritt 2: pubspec.yaml konfigurieren

yaml
flutter:
  assets:
    - assets/images/
    - assets/images/logo.png  # Oder spezifisch

Schritt 3: Bild laden

dart
Image.asset(
  'assets/images/logo.png',
  width: 100,
  height: 100,
)

Icon-Widget

dart
Icon(
  Icons.home,          // Icon-Typ (Material Icons)
  size: 48,            // Größe
  color: Colors.blue,  // Farbe
)

// Häufige Icons:
// Icons.home, Icons.settings, Icons.person
// Icons.add, Icons.delete, Icons.edit
// Icons.favorite, Icons.share

5.3 Button-Widgets (häufig verwendet)

ElevatedButton (am häufigsten verwendet)

dart
ElevatedButton(
  onPressed: () {
    print('Button geklickt!');
  },
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.blue,  // Hintergrundfarbe
    foregroundColor: Colors.white,  // Textfarbe
    padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8),
    ),
  ),
  child: const Text('Klick mich'),
)

TextButton (Text-Button)

dart
TextButton(
  onPressed: () {
    print('TextButton geklickt!');
  },
  child: const Text('Abbrechen'),
)

OutlinedButton (Button mit Rahmen)

dart
OutlinedButton(
  onPressed: () {
    print('OutlinedButton geklickt!');
  },
  style: OutlinedButton.styleFrom(
    side: const BorderSide(color: Colors.blue),  // Rahmen
  ),
  child: const Text('Rahmen-Button'),
)

IconButton (Icon-Button)

dart
IconButton(
  onPressed: () {
    print('Icon geklickt!');
  },
  icon: const Icon(Icons.favorite),
  color: Colors.red,
  tooltip: 'Favorit',  // Tooltip (bei gedrückthalten)
)

5.4 TextField-Widget (Eingabefeld)

Grundlegende Verwendung

dart
TextField(
  decoration: InputDecoration(
    labelText: 'Benutzername',       // Label
    hintText: 'Geben Sie Namen ein', // Platzhalter
    prefixIcon: const Icon(Icons.person), // Icon vor Text
    border: OutlineInputBorder(       // Rahmen
      borderRadius: BorderRadius.circular(8),
    ),
  ),
  onChanged: (value) {               // Eingabe ändert sich
    print('Eingabe: $value');
  },
)

Erweiterte Eigenschaften

dart
TextField(
  obscureText: true,  // Passwort verbergen
  maxLength: 20,      // Maximale Länge
  keyboardType: TextInputType.emailAddress,  // Tastaturtyp
  enabled: true,       // Aktiviert/deaktiviert
  controller: _controller,  // Text-Controller (für Zugriff auf Text)
  
  decoration: InputDecoration(
    labelText: 'E-Mail',
    errorText: 'Ungültige E-Mail',  // Fehlermeldung
    suffixIcon: IconButton(           // Icon am Ende
      icon: Icon(Icons.clear),
      onPressed: () {
        _controller.clear();
      },
    ),
  ),
)

TextEditingController verwenden

dart
class _MyPageState extends State<MyPage> {
  final TextEditingController _controller = TextEditingController();
  
  @override
  void dispose() {
    _controller.dispose();  // WICHTIG: Controller freigeben!
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        TextField(
          controller: _controller,
          decoration: const InputDecoration(labelText: 'Name'),
        ),
        ElevatedButton(
          onPressed: () {
            print('Eingabe: ${_controller.text}');  // Text abrufen
            _controller.clear();  // Text löschen
          },
          child: const Text('Senden'),
        ),
      ],
    );
  }
}

5.5 Andere Basis-Widgets

Container (Container-Widget)

dart
Container(
  width: 200,              // Breite
  height: 100,             // Höhe
  padding: const EdgeInsets.all(16),  // Innenabstand
  margin: const EdgeInsets.all(8),    // Außenabstand
  decoration: BoxDecoration(
    color: Colors.blue.shade100,      // Hintergrundfarbe
    borderRadius: BorderRadius.circular(8),  // Rahmenradius
    border: Border.all(color: Colors.blue), // Rahmen
    boxShadow: [                       // Schatten
      BoxShadow(
        color: Colors.grey.withOpacity(0.5),
        spreadRadius: 2,
        blurRadius: 4,
        offset: const Offset(0, 2),
      ),
    ],
  ),
  child: const Text('Container Inhalt'),
)

SizedBox (Größen-Box)

dart
// Abstand schaffen
SizedBox(height: 20)  // Vertikaler Abstand
SizedBox(width: 20)   // Horizontaler Abstand

// Feste Größe
SizedBox(
  width: 100,
  height: 50,
  child: ElevatedButton(
    onPressed: () {},
    child: const Text('Klick'),
  ),
)

Icon (Icon-Widget)

Bereits in Abschnitt 5.2 behandelt.

5.6 Praxisbeispiel: Einfache Login-Seite erstellen

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

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

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  
  void _login() {
    final username = _usernameController.text;
    final password = _passwordController.text;
    
    if (username == 'admin' && password == '123456') {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Login erfolgreich!')),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Login fehlgeschlagen!')),
      );
    }
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // Logo
            const Icon(Icons.lock, size: 80, color: Colors.blue),
            const SizedBox(height: 32),
            
            // Benutzername-Eingabe
            TextField(
              controller: _usernameController,
              decoration: const InputDecoration(
                labelText: 'Benutzername',
                hintText: 'Geben Sie Benutzernamen ein',
                prefixIcon: Icon(Icons.person),
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 16),
            
            // Passwort-Eingabe
            TextField(
              controller: _passwordController,
              obscureText: true,  // Passwort verbergen
              decoration: const InputDecoration(
                labelText: 'Passwort',
                hintText: 'Geben Sie Passwort ein',
                prefixIcon: Icon(Icons.lock),
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 24),
            
            // Login-Button
            SizedBox(
              width: double.infinity,  // Volle Breite
              child: ElevatedButton(
                onPressed: _login,
                style: ElevatedButton.styleFrom(
                  padding: const EdgeInsets.symmetric(vertical: 16),
                ),
                child: const Text('Login', style: TextStyle(fontSize: 18)),
              ),
            ),
            
            const SizedBox(height: 16),
            
            // Abbrechen-Button
            TextButton(
              onPressed: () {
                _usernameController.clear();
                _passwordController.clear();
              },
              child: const Text('Abbrechen'),
            ),
          ],
        ),
      ),
    );
  }
  
  @override
  void dispose() {
    _usernameController.dispose();
    _passwordController.dispose();
    super.dispose();
  }
}

Zusammenfassung

In diesem Kapitel haben Sie:

  • ✅ Text-Widget mit Styling gelernt
  • ✅ Image-Widget (Netzwerk & lokal) verwendet
  • ✅ Button-Widgets (ElevatedButton, TextButton, etc.) gemeistert
  • ✅ TextField-Widget mit Controller implementiert
  • ✅ Container, SizedBox, Icon verstanden
  • ✅ Eine einfache Login-Seite erstellt

Nächstes Kapitel: Wir werden Flutter-Layouts lernen (Row, Column, Stack, etc.).


Übungsaufgaben:

  1. Erstellen Sie eine Profil-Seite mit Bild, Name und Bio (Text, Image, Container verwenden)
  2. Erstellen Sie ein Registrierungsformular (mehrere TextFields mit Validierung)
  3. Erstellen Sie eine Schaltfläche mit Icon und Text (ElevatedButton mit Row-Kindern)
  4. Experimentieren Sie mit Container-Dekoration (Farbe, Rahmen, Schatten, Radius)

Häufige Fehler:

  • controller.dispose() vergessen → Speicherleck!
  • setState() in StatelessWidget verwenden wollen → Verwenden Sie StatefulWidget!
  • ❌ Bilder ohne pubspec.yaml Konfiguration laden → flutter pub get ausführen
  • obscureText: true vergessen, wenn Passwort verborgen werden soll

Frei für alle Anfänger