-
Notifications
You must be signed in to change notification settings - Fork 26.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
InheritedWidget depending on the result of "MediaQuery.of(context)" does not work after navigation #13484
Comments
If you dump the widget tree (press "w" in the "flutter run" console),
you'll see that you've put the MyInheritedWidget inside the "/" route of
your MaterialApp. When you switch to another route, the MyInheritedWidget
is still in the "/" route (the home route), and your new route doesn't have
it.
You can put your widget outside the MaterialApp, though in your case that
won't work well since you depend on the MediaQuery. You could also put the
MyInheritedWidget around each of your routes, though that would require
extra code.
Without knowing more what the MyInheritedWidget is intended to do, it's
hard to say exactly what the right solution is.
HTH.
On Mon, Dec 11, 2017 at 11:23 AM Gábor Vass ***@***.***> wrote:
So I have a custom InheritedWidget that is depending on the result of
MediaQuery.of(context) (basically, for dynamic dimensions depending on
device width/height, would be very useful for rotation), which works
perfectly, up until I navigate to a different route, after that, the
of(context) mechanism returns null. Please see the example code below,
tap on "Tap to navigate" button, that would replace the currently visible
ConsumerWidget with a new instance of ConsumerWidget, and observe the
crash.
I don't really understand why this is happening, if I had to guess, an
InheritedWidget depending on another InheritedWidget doesn't seem to keep
working after a navigation event. Am I doing something wrong? Is there an
alternate way?
Steps to Reproduce
import 'package:flutter/material.dart';
void main() {
runApp(new TestApp());
}
class TestApp extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return new MaterialApp(
home: new Builder(
builder: (context) {
return new MyInheritedWidget(
data: MediaQuery.of(context),
child: new ConsumerWidget(),
);
},
),
);
}
}
class MyInheritedWidget extends InheritedWidget {
static MyInheritedWidget of(BuildContext context) =>
context.inheritFromWidgetOfExactType(MyInheritedWidget);
final MediaQueryData _data;
MyInheritedWidget({
Key key,
MediaQueryData data,
Widget child,
})
:
_data = data,
super(key: key, child: child);
@OverRide
bool updateShouldNotify(MyInheritedWidget oldWidget) =>
_data != oldWidget._data;
String get deviceWidth => _data.size.width.toString();
}
class ConsumerWidget extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Device width is ${MyInheritedWidget .of(context) .deviceWidth}'),
),
body: new Center(
child: new FlatButton(
child: new Text('Tap to navigate'),
onPressed: () => _navigate(context),
),
),
);
}
void _navigate(BuildContext context) {
Navigator.of(context)
..pop()
..push(
new MaterialPageRoute(
builder: (_) => new ConsumerWidget(),
),
);
}
}
Screenshot right after tapping on navigation button in example code.
<https://i.imgur.com/ABPXCb0.png>
The exception log:
Logs
I/flutter ( 5389): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 5389): The following NoSuchMethodError was thrown building ConsumerWidget(dirty):
I/flutter ( 5389): The getter 'deviceWidth' was called on null.
I/flutter ( 5389): Receiver: null
I/flutter ( 5389): Tried calling: deviceWidth
I/flutter ( 5389):
I/flutter ( 5389): When the exception was thrown, this was the stack:
I/flutter ( 5389): #0 Object.noSuchMethod (dart:core-patch/dart:core/object_patch.dart:46)
I/flutter ( 5389): #1 ConsumerWidget.build (file:///C:/Git/commuter/lib/main.dart:54)
I/flutter ( 5389): #2 StatelessElement.build (package:flutter/src/widgets/framework.dart:3599)
I/flutter ( 5389): #3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3544)
I/flutter ( 5389): #4 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #5 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #6 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #7 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #8 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #9 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #10 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #11 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #12 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #13 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #14 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #15 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #16 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #17 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #18 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #19 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #20 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #21 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4532)
I/flutter ( 5389): #22 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #23 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #24 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4532)
I/flutter ( 5389): #25 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #26 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #27 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #28 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #29 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #30 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3662)
I/flutter ( 5389): #31 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #32 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #33 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #34 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #35 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #36 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #37 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #38 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #39 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #40 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4532)
I/flutter ( 5389): #41 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #42 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #43 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4532)
I/flutter ( 5389): #44 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #45 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #46 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #47 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #48 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #49 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #50 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #51 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #52 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4532)
I/flutter ( 5389): #53 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #54 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #55 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #56 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #57 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #58 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3662)
I/flutter ( 5389): #59 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #60 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #61 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #62 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #63 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #64 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #65 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3662)
I/flutter ( 5389): #66 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #67 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #68 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #69 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #70 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #71 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3524)
I/flutter ( 5389): #72 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3662)
I/flutter ( 5389): #73 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3519)
I/flutter ( 5389): #74 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2857)
I/flutter ( 5389): #75 Element.updateChild (package:flutter/src/widgets/framework.dart:2660)
I/flutter ( 5389): #76 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4319)
I/flutter ( 5389): #77 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4647)
I/flutter ( 5389): #78 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #79 _TheatreElement.update (package:flutter/src/widgets/overlay.dart:507)
I/flutter ( 5389): #80 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #81 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #82 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #83 StatefulElement.update (package:flutter/src/widgets/framework.dart:3681)
I/flutter ( 5389): #84 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #85 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #86 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #87 ProxyElement.update (package:flutter/src/widgets/framework.dart:3791)
I/flutter ( 5389): #88 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #89 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4539)
I/flutter ( 5389): #90 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #91 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #92 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #93 StatefulElement.update (package:flutter/src/widgets/framework.dart:3681)
I/flutter ( 5389): #94 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #95 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4539)
I/flutter ( 5389): #96 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #97 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4539)
I/flutter ( 5389): #98 Element.updateChild (package:flutter/src/widgets/framework.dart:2649)
I/flutter ( 5389): #99 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3556)
I/flutter ( 5389): #100 Element.rebuild (package:flutter/src/widgets/framework.dart:3445)
I/flutter ( 5389): #101 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2193)
I/flutter ( 5389): #102 BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:611)
I/flutter ( 5389): #103 BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:203)
I/flutter ( 5389): #104 BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:916)
I/flutter ( 5389): #105 BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:856)
I/flutter ( 5389): #106 BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:768)
I/flutter ( 5389): #107 _invoke (file:///b/build/slave/Linux_Engine/build/src/flutter/lib/ui/hooks.dart:113)
I/flutter ( 5389): #108 _drawFrame (file:///b/build/slave/Linux_Engine/build/src/flutter/lib/ui/hooks.dart:102)
I/flutter ( 5389): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter ( 5389): Another exception was thrown: NoSuchMethodError: The getter 'deviceWidth' was called on null.
This is happening both on android emulators and iOS simulators.
Flutter Doctor
[√] Flutter (on Microsoft Windows [Version 10.0.16299.64], locale en-US, channel master)
• Flutter at C:\flutter
• Framework revision 0c09179 (2 days ago), 2017-12-09 22:04:06 -0800
• Engine revision edb0201
• Tools Dart version 1.25.0-dev.11.0
• Engine Dart version 2.0.0-edge.a38ac7cf127f4611c873c2f2d523c06ce06b1342
[√] Android toolchain - develop for Android devices (Android SDK 27.0.0)
• Android SDK at C:\android-sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-27, build-tools 27.0.0
• ANDROID_HOME = C:\android-sdk
• Java binary at: C:\android-studio\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b01)
[√] Android Studio (version 3.0)
• Android Studio at C:\android-studio
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b01)
[√] Connected devices
• Android SDK built for x86 • emulator-5554 • android-x86 • Android 8.0.0 (API 26) (emulator)
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#13484>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAhpHF0T_yNBgtoo4vgQK-p8YLEIv5cxks5s_YEzgaJpZM4Q9504>
.
--
…--
Ian Hickson
😸
|
Ahhhhhhhhhhh I understand it now. The thing that confused me a lot is, I used a similar approach for theming colors, but the outer most widget was the theming inherited widget, "outside of the "/" route", and the So yeah, the solution is, to move the widget depending on Thank you, that helped! |
Just to drop a solution: import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class AppDimensions extends InheritedWidget {
static AppDimensions of(BuildContext context) =>
context.inheritFromWidgetOfExactType(AppDimensions);
AppDimensions({
Key key,
@required Widget child,
}) : super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) => false;
double _fix(double value) => value;
MediaQueryData _data(BuildContext context) => MediaQuery.of(context);
static const _cardMinimumWidth = 296.0;
int cardCount(BuildContext context) =>
max(_data(context).size.width ~/ _cardMinimumWidth, 1);
double get paddingSmall => _fix(4.0);
double get paddingMedium => _fix(8.0);
double get paddingLarge => _fix(16.0);
} This way, I can access dimensions similar as I would access themed colors. The padding values don't need Not the most elegant solution, but for a first iteration, everything seems to work. |
Yeah, that makes sense. You could also just have your |
I wasn't really satisfied with the solution I came up with, so I decided to dig deeper. I think I came up with something that is much better, and everything works as I expect it should work. However, I'm not sure how future proof I am, some insight would be appreciated. What I did was, search for when return new MediaQuery(
data: new MediaQueryData.fromWindow(ui.window),
child: new Localizations(
locale: widget.locale ?? _locale,
delegates: _localizationsDelegates.toList(),
// This Builder exists to provide a context below the Localizations widget.
// The onGenerateCallback() can refer to Localizations via its context
// parameter.
child: new Builder(
builder: (BuildContext context) {
String title = widget.title;
if (widget.onGenerateTitle != null) {
title = widget.onGenerateTitle(context);
assert(title != null, 'onGenerateTitle must return a non-null String');
}
return new Title(
title: title,
color: widget.color,
child: result,
);
},
),
),
); So, after that, I wrapped my child: new MediaQuery(
data: new MediaQueryData.fromWindow(ui.window),
child: new Builder(
builder: (context) {
return new AppDimensions(
data: MediaQuery.of(context),
child: new Builder(
builder: (
context) {
return new MaterialApp(
title: _title,
theme: _theme,
home: new HomeScreen(),
);
},
),
);
},
),
), To watch for the changes, I have set up my own @override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
} I handle the events the following way: @override
void didChangeAppLifecycleState(AppLifecycleState state) {}
@override
void didChangeLocale(Locale locale) {}
@override
void didChangeMetrics() => setState(() {});
@override
void didChangeTextScaleFactor() => setState(() {});
@override
void didHaveMemoryPressure() {}
@override
Future<bool> didPopRoute() => new Future.value(false);
@override
Future<bool> didPushRoute(String route) => new Future.value(false); Except the metrics and text scale factor, I don't care about any event, so I won't force a rebuild for them, someone else will anyway. So, basically I have created my own The only question I have is, am I doing something wrong, or not future proof, or everything seems to be in order, and I am safe to commit (at least for now) to this solution? |
It's certainly more work than we'd like you to need to do, but I believe it's using the API as intended. |
|
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
So I have a custom
InheritedWidget
that is depending on the result ofMediaQuery.of(context)
(basically, for dynamic dimensions depending on device width/height, would be very useful for rotation), which works perfectly, up until I navigate to a different route, after that, theof(context)
mechanism returnsnull
. Please see the example code below, tap on "Tap to navigate" button, that would replace the currently visibleConsumerWidget
with a new instance ofConsumerWidget
, and observe the crash.I don't really understand why this is happening, if I had to guess, an
InheritedWidget
depending on anotherInheritedWidget
doesn't seem to keep working after a navigation event. Am I doing something wrong? Is there an alternate way?Steps to Reproduce
Screenshot right after tapping on navigation button in example code.
The exception log:
Logs
This is happening both on android emulators and iOS simulators.
Flutter Doctor
The text was updated successfully, but these errors were encountered: