Flutter-Formulare und Validierung
Dieser Abschnitt führt in die Erstellung, Validierung und Verarbeitung der Übermittlung von Formularen in Flutter ein.
TextFormField - Formulareingabe
TextFormField ist ein TextField, das speziell für Formulare entwickelt wurde, mit integrierter Unterstützung für Validierung.
Beispiel: Einfaches Formular
class LoginForm extends StatefulWidget {
const LoginForm({super.key});
@override
State<LoginForm> createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
// Formularschlüssel (zur Validierung)
final _formKey = GlobalKey<FormState>();
// Eingabe-Controller
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
@override
void dispose() {
_usernameController.dispose();
_passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
// Benutzername-Eingabe
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(
labelText: Benutzername,
prefixIcon: Icon(Icons.person),
),
// Validator
validator: (value) {
if (value == null || value.isEmpty) {
return 'Bitte Benutzernamen eingeben';
}
if (value.length < 3) {
return 'Benutzername muss mindestens 3 Zeichen lang sein';
}
return null;
},
),
const SizedBox(height: 16),
// Passwort-Eingabe
TextFormField(
controller: _passwordController,
obscureText: true, // Passwort verbergen
decoration: const InputDecoration(
labelText: Passwort,
prefixIcon: Icon(Icons.lock),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Bitte Passwort eingeben';
}
if (value.length < 6) {
return 'Passwort muss mindestens 6 Zeichen lang sein';
}
return null;
},
),
const SizedBox(height: 24),
// Absenden-Schaltfläche
ElevatedButton(
onPressed: _submit,
child: const Text('Anmelden'),
),
],
),
);
}
void _submit() {
// Formular validieren
if (_formKey.currentState?.validate() ?? false) {
// Validierung erfolgreich
print('Benutzername: ${_usernameController.text}');
print('Passwort: ${_passwordController.text}');
// An Server senden...
} else {
// Validierung fehlgeschlagen
print('Formularvalidierung fehlgeschlagen');
}
}
}
const LoginForm({super.key});
@override
State<LoginForm> createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
// Formularschlüssel (zur Validierung)
final _formKey = GlobalKey<FormState>();
// Eingabe-Controller
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
@override
void dispose() {
_usernameController.dispose();
_passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
// Benutzername-Eingabe
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(
labelText: Benutzername,
prefixIcon: Icon(Icons.person),
),
// Validator
validator: (value) {
if (value == null || value.isEmpty) {
return 'Bitte Benutzernamen eingeben';
}
if (value.length < 3) {
return 'Benutzername muss mindestens 3 Zeichen lang sein';
}
return null;
},
),
const SizedBox(height: 16),
// Passwort-Eingabe
TextFormField(
controller: _passwordController,
obscureText: true, // Passwort verbergen
decoration: const InputDecoration(
labelText: Passwort,
prefixIcon: Icon(Icons.lock),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Bitte Passwort eingeben';
}
if (value.length < 6) {
return 'Passwort muss mindestens 6 Zeichen lang sein';
}
return null;
},
),
const SizedBox(height: 24),
// Absenden-Schaltfläche
ElevatedButton(
onPressed: _submit,
child: const Text('Anmelden'),
),
],
),
);
}
void _submit() {
// Formular validieren
if (_formKey.currentState?.validate() ?? false) {
// Validierung erfolgreich
print('Benutzername: ${_usernameController.text}');
print('Passwort: ${_passwordController.text}');
// An Server senden...
} else {
// Validierung fehlgeschlagen
print('Formularvalidierung fehlgeschlagen');
}
}
}
Gängige Validatoren
Beispiel: Häufige Validierungsregeln
// Benutzername validieren
String? validateUsername(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Benutzernamen eingeben';
}
if (!RegExp(r'^[a-zA-Z0-9_]+$').hasMatch(value)) {
return 'Darf nur Buchstaben, Zahlen und Unterstriche enthalten';
}
return null;
}
// E-Mail validieren
String? validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte E-Mail eingeben';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) {
return Bitte geben Sie eine gültige E-Mail-Adresse ein;
}
return null;
}
// Passwortstärke validieren
String? validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Passwort eingeben';
}
if (value.length < 8) {
return 'Das Passwort muss mindestens 8 Zeichen lang sein';
}
if (!RegExp(r'[A-Z]').hasMatch(value)) {
return 'Das Passwort muss mindestens einen Großbuchstaben enthalten';
}
if (!RegExp(r'[0-9]').hasMatch(value)) {
return 'Das Passwort muss mindestens eine Zahl enthalten';
}
return null;
}
// Telefonnummer validieren
String? validatePhone(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Telefonnummer eingeben';
}
final phoneRegex = RegExp(r'^1[3-9]\d{9}$');
if (!phoneRegex.hasMatch(value)) {
return 'Bitte eine gültige Telefonnummer eingeben';
}
return null;
}
// Prüfen, ob Passwörter übereinstimmen
String? validateConfirmPassword(String? value, String password) {
if (value == null || value.isEmpty) {
return 'Bitte Passwort bestätigen';
}
if (value != password) {
return 'Die beiden Passwörter stimmen nicht überein';
}
return null;
}
String? validateUsername(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Benutzernamen eingeben';
}
if (!RegExp(r'^[a-zA-Z0-9_]+$').hasMatch(value)) {
return 'Darf nur Buchstaben, Zahlen und Unterstriche enthalten';
}
return null;
}
// E-Mail validieren
String? validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte E-Mail eingeben';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) {
return Bitte geben Sie eine gültige E-Mail-Adresse ein;
}
return null;
}
// Passwortstärke validieren
String? validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Passwort eingeben';
}
if (value.length < 8) {
return 'Das Passwort muss mindestens 8 Zeichen lang sein';
}
if (!RegExp(r'[A-Z]').hasMatch(value)) {
return 'Das Passwort muss mindestens einen Großbuchstaben enthalten';
}
if (!RegExp(r'[0-9]').hasMatch(value)) {
return 'Das Passwort muss mindestens eine Zahl enthalten';
}
return null;
}
// Telefonnummer validieren
String? validatePhone(String? value) {
if (value == null || value.isEmpty) {
return 'Bitte Telefonnummer eingeben';
}
final phoneRegex = RegExp(r'^1[3-9]\d{9}$');
if (!phoneRegex.hasMatch(value)) {
return 'Bitte eine gültige Telefonnummer eingeben';
}
return null;
}
// Prüfen, ob Passwörter übereinstimmen
String? validateConfirmPassword(String? value, String password) {
if (value == null || value.isEmpty) {
return 'Bitte Passwort bestätigen';
}
if (value != password) {
return 'Die beiden Passwörter stimmen nicht überein';
}
return null;
}
Komplexes Formularbeispiel
Beispiel: Registrierungsformular
class RegisterForm extends StatefulWidget {
const RegisterForm({super.key});
@override
State<RegisterForm> createState() => _RegisterFormState();
}
class _RegisterFormState extends State<RegisterForm> {
final _formKey = GlobalKey<FormState>();
final _usernameController = TextEditingController();
final _emailController = TextEditingController();
final _phoneController = TextEditingController();
final _passwordController = TextEditingController();
final _confirmPasswordController = TextEditingController();
bool _acceptTerms = false;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(16),
children: [
// Benutzername
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(labelText: Benutzername),
validator: validateUsername,
),
const SizedBox(height: 16),
// E-Mail
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(labelText: E-Mail),
validator: validateEmail,
),
const SizedBox(height: 16),
// Telefonnummer
TextFormField(
controller: _phoneController,
keyboardType: TextInputType.phone,
decoration: const InputDecoration(labelText: 'Telefonnummer'),
validator: validatePhone,
),
const SizedBox(height: 16),
// Passwort
TextFormField(
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(labelText: Passwort),
validator: validatePassword,
),
const SizedBox(height: 16),
// Passwort bestätigen
TextFormField(
controller: _confirmPasswordController,
obscureText: true,
decoration: const InputDecoration(labelText: Passwort bestätigen),
validator: (value) => validateConfirmPassword(
value,
_passwordController.text,
),
),
const SizedBox(height: 16),
// Den Bedingungen zustimmen
CheckboxListTile(
value: _acceptTerms,
onChanged: (value) {
setState(() {
_acceptTerms = value ?? false;
});
},
title: const Text(Ich stimme den Nutzungsbedingungen zu),
controlAffinity: ListTileControlAffinity.leading,
),
const SizedBox(height: 24),
// Absenden-Schaltfläche
ElevatedButton(
onPressed: _acceptTerms ? _submit : null,
child: const Text(Registrieren),
),
],
),
);
}
void _submit() {
if (_formKey.currentState?.validate() ?? false) {
// Formular absenden
print(Registrierung erfolgreich!);
}
}
@override
void dispose() {
_usernameController.dispose();
_emailController.dispose();
_phoneController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
super.dispose();
}
}
const RegisterForm({super.key});
@override
State<RegisterForm> createState() => _RegisterFormState();
}
class _RegisterFormState extends State<RegisterForm> {
final _formKey = GlobalKey<FormState>();
final _usernameController = TextEditingController();
final _emailController = TextEditingController();
final _phoneController = TextEditingController();
final _passwordController = TextEditingController();
final _confirmPasswordController = TextEditingController();
bool _acceptTerms = false;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(16),
children: [
// Benutzername
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(labelText: Benutzername),
validator: validateUsername,
),
const SizedBox(height: 16),
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(labelText: E-Mail),
validator: validateEmail,
),
const SizedBox(height: 16),
// Telefonnummer
TextFormField(
controller: _phoneController,
keyboardType: TextInputType.phone,
decoration: const InputDecoration(labelText: 'Telefonnummer'),
validator: validatePhone,
),
const SizedBox(height: 16),
// Passwort
TextFormField(
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(labelText: Passwort),
validator: validatePassword,
),
const SizedBox(height: 16),
// Passwort bestätigen
TextFormField(
controller: _confirmPasswordController,
obscureText: true,
decoration: const InputDecoration(labelText: Passwort bestätigen),
validator: (value) => validateConfirmPassword(
value,
_passwordController.text,
),
),
const SizedBox(height: 16),
// Den Bedingungen zustimmen
CheckboxListTile(
value: _acceptTerms,
onChanged: (value) {
setState(() {
_acceptTerms = value ?? false;
});
},
title: const Text(Ich stimme den Nutzungsbedingungen zu),
controlAffinity: ListTileControlAffinity.leading,
),
const SizedBox(height: 24),
// Absenden-Schaltfläche
ElevatedButton(
onPressed: _acceptTerms ? _submit : null,
child: const Text(Registrieren),
),
],
),
);
}
void _submit() {
if (_formKey.currentState?.validate() ?? false) {
// Formular absenden
print(Registrierung erfolgreich!);
}
}
@override
void dispose() {
_usernameController.dispose();
_emailController.dispose();
_phoneController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
super.dispose();
}
}
Weitere ErweiterungenDie Formularvalidierung sollte sowohl clientseitig (für die Benutzererfahrung) als auch serverseitig (zur Sicherheit) durchgeführt werden; verlassen Sie sich nicht ausschließlich auf die clientseitige Validierung.