InheritedWidget ist ein spezielles Widget in Flutter, das Daten im Widget-Baum nach unten weitergibt, ohne sie explizit durch Konstruktoren zu reichen. Kind-Widgets greifen über BuildContext auf Daten zu und abonnieren automatisch Aktualisierungen. Wenn sich Daten in InheritedWidget ändern, werden alle abhängigen Widgets neu erstellt. Laut Flutter API Reference, 2025 bildet InheritedWidget die Grundlage von Theme, MediaQuery, Localizations und der meisten State-Management-Bibliotheken.
Wichtige Punkte
InheritedWidget ist ein Widget, das seine Daten für alle Nachkommen im Widget Tree verfügbar macht. Im Gegensatz zu einem normalen Widget, das Daten nur über Konstruktoren an Kind-Elemente weitergibt, ermöglicht InheritedWidget jedem Widget im Teilbaum den Zugriff auf Daten ohne eine Parameterverschachtelung. Dies löst das Problem des „Prop Drilling“ – das Reichen von Daten durch viele vermittelnde Widgets, die diese Daten selbst nicht verwenden.
Flutter enthält mehrere integrierte InheritedWidgets: Theme (Farbschema und Stile), MediaQuery (Bildschirmgröße, Ausrichtung, Pixeldichte), Localizations (lokalisierte Zeichenfolgen), Directionality (Textrichtung), DefaultTextStyle (Standard-Textstil). Diese Widgets werden von Root-Widgets wie MaterialApp gesetzt und sind in der gesamten Anwendung verfügbar.
InheritedWidget hat keinen eigenen Zustand – es speichert Daten, die über den Konstruktor übergeben wurden. Wenn das übergeordnete Element von InheritedWidget mit neuen Daten neu erstellt wird, wird die Methode updateShouldNotify aufgerufen, um alte und neue Daten zu vergleichen. Wenn die Methode true zurückgibt, werden alle abhängigen Widgets für die Neuerstellung markiert. Dies ist ein einfacher, aber effektiver reaktiver Aktualisierungsmechanismus.
Der Datenweitergabemechanismus durch InheritedWidget basiert auf dem Element Tree. Wenn ein Widget dependOnInheritedWidgetOfExactType aufruft, registriert das entsprechende Element eine Abhängigkeit von InheritedElement. Wenn sich InheritedWidget ändert, benachrichtigt InheritedElement alle abhängigen Elemente, die im nächsten Frame neu erstellt werden.
Die Methode dependOnInheritedWidgetOfExactType findet nicht nur InheritedWidget im Baum – sie abonniert das aktuelle Element für Benachrichtigungen. Wenn Sie findAncestorWidgetOfExactType anstelle von dependOn verwenden würden, würde das Widget die Daten erhalten, aber bei Änderungen nicht neu erstellt werden. Dies ist ein wichtiger Unterschied: dependOn ist ein Abonnement, findAncestor eine einmalige Suche.
Wenn ein Widget ein InheritedWidget anfordert, steigt Flutter im Element Tree vom aktuellen Element zur Wurzel auf und überprüft jedes InheritedElement auf Typübereinstimmung. Das erste übereinstimmende InheritedElement wird zurückgegeben. Dies bedeutet, dass das nächste InheritedWidget im Baum Priorität hat – Sie können Daten auf einer bestimmten Ebene überschreiben, indem Sie InheritedWidget näher an den Nachkommen platzieren.
class ThemeData {
final Color primaryColor;
final TextTheme textTheme;
const ThemeData({required this.primaryColor, required this.textTheme});
}
class MyTheme extends InheritedWidget {
final ThemeData data;
const MyTheme({required this.data, required Widget child}) : super(child: child);
static MyTheme of(BuildContext context) {
final widget = context.dependOnInheritedWidgetOfExactType<MyTheme>();
assert(widget != null, "MyTheme not found in tree");
return widget!;
}
@override
bool updateShouldNotify(MyTheme oldWidget) => oldWidget.data != data;
}
In diesem Beispiel verwendet MyTheme eine statische of-Methode, um Daten an Nachkommen bereitzustellen. Die Methode dependOnInheritedWidgetOfExactType registriert eine Abhängigkeit, und updateShouldNotify vergleicht alte und neue Daten, um festzustellen, ob abhängige Widgets neu erstellt werden müssen.
Das Erstellen eines benutzerdefinierten InheritedWidget besteht aus zwei Schritten: Definieren einer Klasse, die InheritedWidget erweitert, und Implementieren einer statischen of-Methode für den Zugriff von Nachkommen. Daten werden über den Konstruktor übergeben, und die Methode updateShouldNotify bestimmt, wann abhängige Widgets neu erstellt werden sollen.
Die Klasse muss InheritedWidget erweitern und Daten über einen Konstruktor mit einem erforderlichen child-Parameter akzeptieren. Daten können von jedem Typ sein: Primitiven, Objekte, Funktionen. Die Hauptregel ist, dass Daten unveränderlich (immutable) sein müssen, damit alte und neue Werte zuverlässig verglichen werden können.
Die statische of-Methode nimmt BuildContext entgegen und gibt InheritedWidget-Daten zurück. Intern ruft sie dependOnInheritedWidgetOfExactType auf, die das nächste InheritedWidget des angegebenen Typs im Baum findet. Wenn InheritedWidget nicht gefunden wird, wirft die Methode eine Ausnahme oder gibt einen Standardwert zurück, je nach Implementierung.
Um auf Daten zuzugreifen, ruft das Widget MyWidget.of(context) innerhalb der build-Methode auf. Flutter abonniert das Widget automatisch für Aktualisierungen. Wenn sich Daten ändern, wird das Widget im nächsten Frame neu erstellt. Dies ermöglicht sauberen und deklarativen Code ohne unnötige Parameter.
class UserPreferences extends InheritedWidget {
final String languageCode;
final bool darkMode;
const UserPreferences({
required this.languageCode,
required this.darkMode,
required Widget child,
}) : super(child: child);
static UserPreferences of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<UserPreferences>()!;
}
@override
bool updateShouldNotify(UserPreferences oldWidget) =>
oldWidget.languageCode != languageCode || oldWidget.darkMode != darkMode;
}
In diesem Beispiel speichert UserPreferences Benutzereinstellungen. Die Methode updateShouldNotify vergleicht jedes Feld einzeln, was unnötige Neuerstellungen verhindert, wenn sich nur ein Parameter ändert. Verwenden Sie einen ähnlichen Ansatz für Ihre eigenen InheritedWidgets mit mehreren Feldern.
updateShouldNotify ist die Schlüsselmethode von InheritedWidget, die bestimmt, ob abhängige Widgets über Datenänderungen benachrichtigt werden müssen. Wenn die Methode false zurückgibt, werden abhängige Widgets nicht neu erstellt, selbst wenn InheritedWidget selbst eine neue Instanz mit denselben Daten erhalten hat. Dies ist für die Leistung von entscheidender Bedeutung.
Vergleichen Sie nur die Felder, die tatsächlich geändert wurden und die Anzeige beeinflussen. Wenn InheritedWidget 10 Felder enthält, aber nur eines die UI beeinflusst, überprüfen Sie nur dieses Feld. Verwenden Sie für Sammlungen einen tiefen Vergleich oder unveränderliche Datenstrukturen. Verwenden Sie nicht == für List oder Map, da diese per Referenz vergleichen.
Der häufigste Fehler ist die Rückgabe von true ohne Vergleich. Dies führt dazu, dass alle abhängigen Widgets bei jeder Elternaktualisierung neu erstellt werden, selbst wenn sich die Daten nicht geändert haben. Der zweite Fehler ist die Rückgabe von false, wenn sich Daten geändert haben, was zu einer veralteten UI führt. Der dritte ist ein komplexer Vergleich, der in jedem Frame ausgeführt wird und die Leistung verlangsamt.
InheritedWidget und Callbacks (Übergeben von Funktionen durch Konstruktoren) lösen unterschiedliche Probleme. InheritedWidget eignet sich für Daten, die von vielen Widgets auf verschiedenen Ebenen des Baums benötigt werden. Callbacks sind praktisch für die unidirektionale Ereignisweitergabe vom übergeordneten zu einem bestimmten untergeordneten Element oder umgekehrt. Die Wahl hängt von der Anwendungsarchitektur und der Aktualisierungshäufigkeit ab.
Verwenden Sie InheritedWidget, wenn Daten von vielen Widgets auf verschiedenen Verschachtelungsebenen benötigt werden: App-Design, Benutzereinstellungen, Geräteinformationen, aktuelle Sitzungsdaten. InheritedWidget ist besonders effektiv für „globale“ Daten, die sich selten ändern, aber in verschiedenen Teilen der UI benötigt werden.
Callbacks (Rückruffunktionen) eignen sich zum Übergeben von Ereignissen von einem untergeordneten Widget an ein übergeordnetes: Tastendruck, Auswahl von Listenelementen, Formularübermittlung. Callbacks geben explizit an, welche Aktionen ein untergeordnetes Element ausführen kann, und erzeugen keine versteckten Abhängigkeiten. Für die Weitergabe von Daten nach unten über eine geringe Anzahl von Ebenen ist es auch einfacher, Konstruktorparameter zu verwenden.
| Kriterium | InheritedWidget | Callbacks |
|---|---|---|
| Richtung | Von oben nach unten (Eltern → Nachkommen) | Von unten nach oben (Kind → Eltern) oder direkt |
| Bereich | Gesamter Teilbaum | Bestimmtes Widget |
| Neuerstellung | Automatisch bei Datenänderung | Manuelles setState erforderlich |
| Komplexität | Mittel (erfordert InheritedWidget-Klasse) | Niedrig (nur eine Funktion) |
Provider und Riverpod sind beliebte State-Management-Bibliotheken in Flutter, die auf InheritedWidget aufbauen. Sie erweitern seine Fähigkeiten: Hinzufügen von ChangeNotifier-Unterstützung, automatische Entsorgung beim Aushängen, verzögerte Initialisierung und vereinfachte Syntax mit Generics.
Provider verwendet InheritedWidget, um ein Objekt beliebigen Typs im Baum nach unten zu reichen. ChangeNotifierProvider verfolgt Änderungen über ChangeNotifier und ruft updateShouldNotify auf, wenn notifyListeners aufgerufen wird. Dies befreit den Entwickler von der manuellen Erstellung von InheritedWidget und der Implementierung von updateShouldNotify.
Direktes InheritedWidget bietet mehr Kontrolle und erfordert keine externen Abhängigkeiten. Provider bietet eine fertige Infrastruktur: Consumer, Selector, MultiProvider, ProxyProvider. Die Wahl hängt von der Anwendungskomplexität ab. Für einfache Projekte ist direktes InheritedWidget ausreichend; für große reduzieren Provider oder Riverpod den Boilerplate-Code.
// Direktes InheritedWidget
class UserProvider extends InheritedWidget {
final UserData userData;
const UserProvider({required this.userData, required Widget child}) : super(child: child);
static UserData of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<UserProvider>()!.userData;
@override
bool updateShouldNotify(UserProvider old) => old.userData != userData;
}
// Provider-Äquivalent
return ChangeNotifierProvider<UserData>(
create: (_) => UserData(),
child: MyApp(),
);
Beide Ansätze im Beispiel lösen dasselbe Problem – die Weitergabe von UserData im Baum nach unten. Provider reduziert die Code-Menge, verbirgt jedoch die Mechanik von InheritedWidget. Direktes InheritedWidget bietet vollständige Kontrolle und Verständnis für das Geschehen, was besonders beim Erlernen von Flutter und beim Debuggen komplexer Neuerstellungsprobleme wichtig ist.
Häufig gestellte Fragen
InheritedWidget macht Daten für alle Nachkommen über BuildContext verfügbar, während ein normales Widget Daten nur über den Konstruktor weitergibt. InheritedWidget abonniert auch Nachkommen für Datenaktualisierungen.
Abhängige Widgets werden nur neu erstellt, wenn updateShouldNotify true zurückgibt. Wenn die Methode korrekt implementiert ist, erfolgt die Neuerstellung nur bei tatsächlicher Datenänderung, nicht bei jeder Eltern-Neuerstellung.
Ja, Sie können beliebig viele InheritedWidgets im selben Baum verwenden. Jedes stellt Daten eines bestimmten Typs bereit, und Widgets können gleichzeitig Daten aus mehreren InheritedWidgets beziehen.
dependOn abonniert das Widget für Aktualisierungen – bei Datenänderung wird das Widget neu erstellt. findAncestor führt eine einmalige Suche ohne Abonnement durch, und das Widget erfährt nichts von Datenänderungen.
Für einfache Zustände (Design, Einstellungen) ist InheritedWidget ausreichend. Für komplexe Zustände mit Geschäftslogik verwenden Sie Provider, Riverpod oder BLoC – sie bauen auf InheritedWidget auf und fügen die notwendige Infrastruktur hinzu.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch