Skip to content

Instantly share code, notes, and snippets.

@PiN73
Last active February 22, 2022 03:43
Show Gist options
  • Save PiN73/c311ca15d54dd905660fe9e2b1c8c337 to your computer and use it in GitHub Desktop.
Save PiN73/c311ca15d54dd905660fe9e2b1c8c337 to your computer and use it in GitHub Desktop.
Flutter: depend on non-nearest InheritedWidget of given type
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