Last active
February 22, 2022 03:43
-
-
Save PiN73/c311ca15d54dd905660fe9e2b1c8c337 to your computer and use it in GitHub Desktop.
Flutter: depend on non-nearest InheritedWidget of given type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
void main() => runApp(const MyApp()); | |
class MyApp extends StatelessWidget { | |
const MyApp({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return const MaterialApp( | |
home: Material( | |
child: Center( | |
child: MyWidget( | |
identity: 'a', | |
child: MyWidget( | |
identity: 'b', | |
child: MyWidget( | |
identity: 'c', | |
child: MyFind(), | |
), | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class MyWidget extends StatelessWidget { | |
final String identity; | |
final Widget child; | |
const MyWidget({ | |
Key? key, | |
required this.identity, | |
required this.child, | |
}) : super(key: key); | |
static _MyWidget dependOnNearest(BuildContext context) { | |
return context.dependOnInheritedWidgetOfExactType<_MyWidget>()!; | |
} | |
static _MyWidget dependOnRoot(BuildContext context) { | |
return context.dependOnRootInheritedWidgetOfExactType<_MyWidget>()!; | |
} | |
static _MyWidget dependOnSpecific( | |
BuildContext context, { | |
required String identity, | |
}) { | |
return context.dependOnSpecificInheritedWidgetOfExactType<_MyWidget>( | |
(widget) => widget.identity == identity, | |
)!; | |
} | |
@override | |
Widget build(BuildContext context) { | |
return _MyWidget( | |
identity: identity, | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Text(identity), | |
Container( | |
padding: const EdgeInsets.all(8), | |
margin: const EdgeInsets.all(8), | |
decoration: BoxDecoration(border: Border.all()), | |
child: child, | |
), | |
], | |
), | |
); | |
} | |
} | |
class _MyWidget extends InheritedWidget { | |
final String identity; | |
const _MyWidget({ | |
Key? key, | |
required this.identity, | |
required Widget child, | |
}) : super(key: key, child: child); | |
@override | |
bool updateShouldNotify(_MyWidget oldWidget) { | |
return identity != oldWidget.identity; | |
} | |
} | |
class MyFind extends StatelessWidget { | |
const MyFind({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
final nearest = MyWidget.dependOnNearest(context); | |
final root = MyWidget.dependOnRoot(context); | |
final mid = MyWidget.dependOnSpecific(context, identity: 'b'); | |
return Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Text('nearest: ${nearest.identity}'), | |
Text('root: ${root.identity}'), | |
Text('mid: ${mid.identity}'), | |
], | |
); | |
} | |
} | |
extension BuildContextX on BuildContext { | |
Iterable<InheritedElement> getElementsForInheritedWidgetsOfExactType< | |
T extends InheritedWidget>() sync* { | |
final element = getElementForInheritedWidgetOfExactType<T>(); | |
if (element != null) { | |
yield element; | |
Element? parent; | |
element.visitAncestorElements((element) { | |
parent = element; | |
return false; | |
}); | |
if (parent != null) { | |
yield* parent!.getElementsForInheritedWidgetsOfExactType<T>(); | |
} | |
} | |
} | |
T? dependOnRootInheritedWidgetOfExactType<T extends InheritedWidget>() { | |
final element = getElementsForInheritedWidgetsOfExactType<T>().lastOrNull; | |
if (element == null) { | |
return null; | |
} | |
return dependOnInheritedElement(element) as T; | |
} | |
T? dependOnSpecificInheritedWidgetOfExactType<T extends InheritedWidget>( | |
bool Function(T) test, | |
) { | |
final element = getElementsForInheritedWidgetsOfExactType<T>() | |
.where((element) => test(element.widget as T)) | |
.firstOrNull; | |
if (element == null) { | |
return null; | |
} | |
return dependOnInheritedElement(element) as T; | |
} | |
} | |
extension IterableX<E> on Iterable<E> { | |
E? get firstOrNull { | |
Iterator<E> it = iterator; | |
if (!it.moveNext()) { | |
return null; | |
} | |
return it.current; | |
} | |
E? get lastOrNull { | |
Iterator<E> it = iterator; | |
if (!it.moveNext()) { | |
return null; | |
} | |
E result; | |
do { | |
result = it.current; | |
} while (it.moveNext()); | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment