Appearance
Kapitel 5: Basis-Widgets
5.1 Text-Widget
Grundlegende Verwendung
dart
Text('Hallo Flutter!') // Einfacher TextText-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üllenBoxFit.contain: Skaliert, um komplett sichtbar zu seinBoxFit.cover: Deckt gesamten Container ab (beschnitten)BoxFit.fitWidth: Passt Breite anBoxFit.fitHeight: Passt Höhe anBoxFit.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 spezifischSchritt 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.share5.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:
- Erstellen Sie eine Profil-Seite mit Bild, Name und Bio (Text, Image, Container verwenden)
- Erstellen Sie ein Registrierungsformular (mehrere TextFields mit Validierung)
- Erstellen Sie eine Schaltfläche mit Icon und Text (ElevatedButton mit Row-Kindern)
- Experimentieren Sie mit Container-Dekoration (Farbe, Rahmen, Schatten, Radius)
Häufige Fehler:
- ❌
controller.dispose()vergessen → Speicherleck! - ❌
setState()inStatelessWidgetverwenden wollen → Verwenden SieStatefulWidget! - ❌ Bilder ohne
pubspec.yamlKonfiguration laden →flutter pub getausführen - ❌
obscureText: truevergessen, wenn Passwort verborgen werden soll
