Flutter-Navigation und Routing
Dieser Abschnitt stellt die Navigations- und Routing-Mechanismen in Flutter vor, einschließlich Seitenübergängen, Parameterübergabe und benannten Routen.
Navigator-Grundlagen
Flutter verwendet Navigator für die Seitenverwaltung und implementiert Seitenübergänge basierend auf einer Stapelstruktur.
Beispiel: Grundlegende Seitennavigation
// Zu einer neuen Seite navigieren
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const DetailPage(),
),
);
// Zurück zur vorherigen Seite
Navigator.of(context).pop();
// Mit Ergebnis zurückkehren
Navigator.of(context).pop('Returned data');
// Aktuelle Seite ersetzen (keine Rückkehr möglich)
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const HomePage(),
),
);
// Zur Wurzelseite zurückkehren
Navigator.of(context).popUntil((route) => route.isFirst);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const DetailPage(),
),
);
// Zurück zur vorherigen Seite
Navigator.of(context).pop();
// Mit Ergebnis zurückkehren
Navigator.of(context).pop('Returned data');
// Aktuelle Seite ersetzen (keine Rückkehr möglich)
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const HomePage(),
),
);
// Zur Wurzelseite zurückkehren
Navigator.of(context).popUntil((route) => route.isFirst);
MaterialPageRoute vs CupertinoPageRoute
Beispiel: Seitenübergangsanimationen auf verschiedenen Plattformen
// Android-Stil - steigt von unten auf
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const DetailPage(),
),
);
// iOS-Stil - gleitet von rechts herein
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => const DetailPage(),
),
);
// Benutzerdefinierter Übergangseffekt
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return const DetailPage();
},
transitionsBuilder: (context, animation, secondaryAnimation, child) {
// Ein-/Ausblendeffekt
return FadeTransition(
opacity: animation,
child: child,
);
},
transitionDuration: const Duration(milliseconds: 300),
),
);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const DetailPage(),
),
);
// iOS-Stil - gleitet von rechts herein
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => const DetailPage(),
),
);
// Benutzerdefinierter Übergangseffekt
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return const DetailPage();
},
transitionsBuilder: (context, animation, secondaryAnimation, child) {
// Ein-/Ausblendeffekt
return FadeTransition(
opacity: animation,
child: child,
);
},
transitionDuration: const Duration(milliseconds: 300),
),
);
Übergeben von Seitenparametern
< h2 class="example">Beispiel: Parameter an eine neue Seite übergeben
// Zur Detailseite springen und Parameter übergeben
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ProductDetailPage(productId: 123),
),
);
// Detailseite empfängt Parameter
class ProductDetailPage extends StatelessWidget {
final int productId;
const ProductDetailPage({
super.key,
required this.productId,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Produkt $productId')),
body: Center(child: Text('Produkt-ID: $productId')),
);
}
}
// Mehrere Parameter übergeben
class UserProfilePage extends StatelessWidget {
final String name;
final int age;
const UserProfilePage({
super.key,
required this.name,
required this.age,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(Startseite von $name)),
body: Center(child: Text('Alter: $age')),
);
}
}
// Springen
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const UserProfilePage(
name: 'Zhang San',
age: 25,
),
),
);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ProductDetailPage(productId: 123),
),
);
// Detailseite empfängt Parameter
class ProductDetailPage extends StatelessWidget {
final int productId;
const ProductDetailPage({
super.key,
required this.productId,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Produkt $productId')),
body: Center(child: Text('Produkt-ID: $productId')),
);
}
}
// Mehrere Parameter übergeben
class UserProfilePage extends StatelessWidget {
final String name;
final int age;
const UserProfilePage({
super.key,
required this.name,
required this.age,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(Startseite von $name)),
body: Center(child: Text('Alter: $age')),
);
}
}
// Springen
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const UserProfilePage(
name: 'Zhang San',
age: 25,
),
),
);
Benannte Route
Die Verwendung benannter Routen kann die Konfiguration von Seitenübergängen vereinfachen.
Beispiel: Konfiguration benannter Routen
void main() {
runApp(
MaterialApp(
// Routing-Tabelle definieren
initialRoute: '/',
routes: {
'/': (context) => const HomePage(),
'/detail': (context) => const DetailPage(),
'/user': (context) => const UserPage(),
'/settings': (context) => const SettingsPage(),
},
),
);
}
// Springen
Navigator.pushNamed(context, '/detail');
// Mit Parametern navigieren
Navigator.pushNamed(context, '/user', arguments: {'name': 'Zhang San', 'age': 25});
// Parameter auf der Zielseite abrufen
class DetailPage extends StatelessWidget {
const DetailPage({super.key});
@override
Widget build(BuildContext context) {
// Die übergebenen Parameter abrufen
final args = ModalRoute.of(context)?.settings.arguments as Map?;
return Scaffold(
appBar: AppBar(title: const Text('Detail Page')),
body: Center(
child: Text(Arguments: $args),
),
);
}
}
runApp(
MaterialApp(
// Routing-Tabelle definieren
initialRoute: '/',
routes: {
'/': (context) => const HomePage(),
'/detail': (context) => const DetailPage(),
'/user': (context) => const UserPage(),
'/settings': (context) => const SettingsPage(),
},
),
);
}
// Springen
Navigator.pushNamed(context, '/detail');
// Mit Parametern navigieren
Navigator.pushNamed(context, '/user', arguments: {'name': 'Zhang San', 'age': 25});
// Parameter auf der Zielseite abrufen
class DetailPage extends StatelessWidget {
const DetailPage({super.key});
@override
Widget build(BuildContext context) {
// Die übergebenen Parameter abrufen
final args = ModalRoute.of(context)?.settings.arguments as Map?;
return Scaffold(
appBar: AppBar(title: const Text('Detail Page')),
body: Center(
child: Text(Arguments: $args),
),
);
}
}
Eine andere Möglichkeit, Werte beim Routing zu übergeben
Beispiel: onGenerateRoute
MaterialApp(
onGenerateRoute: (settings) {
// Je nach Routenname unterschiedliche Seiten zurückgeben
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (_) => const HomePage(),
);
case '/detail':
// Parameter aus Argumenten abrufen
final args = settings.arguments as Map<String, dynamic>?;
return MaterialPageRoute(
builder: (_) => DetailPage(
id: args?['id'] ?? 0,
title: args?['title'] ?? '',
),
);
case '/product':
final productId = settings.name?.split('/').last;
return MaterialPageRoute(
builder: (_) => ProductPage(id: productId ?? ''),
);
default:
return MaterialPageRoute(
builder: (_) => const NotFoundPage(),
);
}
},
)
onGenerateRoute: (settings) {
// Je nach Routenname unterschiedliche Seiten zurückgeben
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (_) => const HomePage(),
);
case '/detail':
// Parameter aus Argumenten abrufen
final args = settings.arguments as Map<String, dynamic>?;
return MaterialPageRoute(
builder: (_) => DetailPage(
id: args?['id'] ?? 0,
title: args?['title'] ?? '',
),
);
case '/product':
final productId = settings.name?.split('/').last;
return MaterialPageRoute(
builder: (_) => ProductPage(id: productId ?? ''),
);
default:
return MaterialPageRoute(
builder: (_) => const NotFoundPage(),
);
}
},
)
Weitere ErweiterungenFür einfache Anwendungen ist das grundlegende Navigator.push ausreichend; für mittlere bis große Anwendungen wird empfohlen, benannte Routen oder Routing-Management-Bibliotheken zu verwenden, um Seiten zentral zu verwalten.