window.padding.top return 0 in release mode

495 views
Skip to first unread message

李少杰

unread,
Jun 4, 2018, 1:06:43 AM6/4/18
to Flutter Dev
Hello flutter,
I was trying to build a custom UI without Material widgets, but I found it wired when dealing with the status bar. In debug mode, everything works fine, but in release mode(start app with flutter run —-release), the top padding retrieved from ui.window is 0.
What’s wrong in the following code? Can I rely on ui.window.padding to implement this UI?
import 'dart:ui' as ui;

import 'package:flutter/widgets.dart';

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Directionality(
textDirection: TextDirection.ltr,
child: Container(
color: const Color(0xFF3333FF),
padding: EdgeInsets.only(top: ui.window.padding.top / ui.window.devicePixelRatio),
child: new Container(
color: const Color(0xFFFFA3A3),
child: new Center(
child: new Container(
color: const Color(0xFF313100),
padding: const EdgeInsets.all(20.0),
child: new Text('Hello, world.')))),
));
}
}

void main() {
runApp(new MyApp());
}
Message has been deleted

Eric Seidel

unread,
Jun 4, 2018, 11:40:46 AM6/4/18
to 李少杰, Flutter Dev
We had a similar bug in our Gallery a while back, see https://github.com/flutter/flutter/issues/5368

--
You received this message because you are subscribed to the Google Groups "Flutter Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
40898093-ac3213a2-67f1-11e8-997f-f946191e02f4.png
40898013-2f5c47a8-67f1-11e8-94ad-c02a30980613.png

Ian Hickson

unread,
Jun 4, 2018, 6:13:55 PM6/4/18
to Eric Seidel, 李少杰, Flutter Dev
Use MediaQuery instead of the window object directly. MediaQuery knows how to listen for notifications that it the values are changing.
--

--
Ian Hickson

😸

李少杰

unread,
Jun 5, 2018, 12:54:50 AM6/5/18
to Ian Hickson, Eric Seidel, Flutter Dev
I changed my codes as follow, and it still doesn’t work in release mode:

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Directionality(
textDirection: TextDirection.ltr,
        child: MediaQuery(
data: MediaQueryData.fromWindow(ui.window),
child: SafeArea(

child: Container(
color: const Color(0xFF3333FF),
              child: new Container(
color: const Color(0xFFFFA3A3),
child: new Center(
child: new Container(
color: const Color(0xFF313100),
padding: const EdgeInsets.all(20.0),
child: new Text('Hello, world.')))),
            ),
),
));
}
I noticed the `data: MediaQueryData.fromWindow(ui.window),` fromWindow just copy padding from ui.window:
/// Creates data for a media query based on the given window.
///
/// If you use this, you should ensure that you also register for
/// notifications so that you can update your [MediaQueryData] when the
/// window's metrics change. For example, see
/// [WidgetsBindingObserver.didChangeMetrics] or [Window.onMetricsChanged].
MediaQueryData.fromWindow(ui.Window window)
: size = window.physicalSize / window.devicePixelRatio,
devicePixelRatio = window.devicePixelRatio,
textScaleFactor = window.textScaleFactor,
padding = new EdgeInsets.fromWindowPadding(window.padding, window.devicePixelRatio),
viewInsets = new EdgeInsets.fromWindowPadding(window.viewInsets, window.devicePixelRatio),
alwaysUse24HourFormat = window.alwaysUse24HourFormat;
Is there any other way to use MediaQuery? How MediaQuery listen for the changing of window.padding?
Thanks to the comments above, "you should ensure that you also register for notifications so that you can update your [MediaQueryData] when the window's metrics change.", then change as follows:
VoidCallback _handleMetricsChanged;


class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return StatefulBuilder(
builder: (context, setState) {
if (_handleMetricsChanged == null) {
_handleMetricsChanged = ui.window.onMetricsChanged;
}
ui.window.onMetricsChanged = () {
_handleMetricsChanged();
setState(() {});
};

return new Directionality(
textDirection: TextDirection.ltr,
            child: MediaQuery(
data: MediaQueryData.fromWindow(ui.window),
child: SafeArea(

child: Container(
color: const Color(0xFF3333FF),
                  child: new Container(
color: const Color(0xFFFFA3A3),
child: new Center(
child: new Container(
color: const Color(0xFF313100),
padding: const EdgeInsets.all(20.0),
child: new Text('Hello, world.')))),
                ),
),
));
},
);
}
}
Aha, it finally works fine both in debug and release mode. So the point is I must listen to `window.onMetricsChanged`, using a custom padding works fine as well:
VoidCallback _handleMetricsChanged;


class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return StatefulBuilder(
builder: (context, setState) {
if (_handleMetricsChanged == null) {
_handleMetricsChanged = ui.window.onMetricsChanged;
}
ui.window.onMetricsChanged = () {
_handleMetricsChanged();
setState(() {});
};

return new Directionality(
textDirection: TextDirection.ltr,
child: Container(
color: const Color(0xFF3333FF),
padding: EdgeInsets.only(top: ui.window.padding.top / ui.window.devicePixelRatio),
child: new Container(
color: const Color(0xFFFFA3A3),
child: new Center(
child: new Container(
color: const Color(0xFF313100),
padding: const EdgeInsets.all(20.0),
child: new Text('Hello, world.')))),
));
      },
);
}
}




Kris Giesing

unread,
Jun 5, 2018, 1:18:15 AM6/5/18
to sslik...@gmail.com, Ian Hickson, Eric Seidel, Flutter Dev
I think you can simplify your solution by using MediaQuery.of: https://docs.flutter.io/flutter/widgets/MediaQuery/of.html. Widgets using that method will be scheduled for rebuild when the data changes, meaning your code doesn't have to do the onMetricsChanged registration manually.

Hope this helps,

- Kris

李少杰

unread,
Jun 5, 2018, 4:33:09 AM6/5/18
to Kris Giesing, Ian Hickson, Eric Seidel, Flutter Dev
I had try `MediaQuery.of(context)` at the first time, but I am not using MaterialApp, so it failed with:

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ The following assertion was thrown building StatefulBuilder(dirty, state:_StatefulBuilderState#24c5a): MediaQuery.of() called with a context that does not contain a MediaQuery. No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of(). This can happen because you do not have a WidgetsApp or MaterialApp widget (those widgets introduce a MediaQuery), or it can happen if the context you use comes from a widget above those widgets. The context used was: StatefulBuilder(dirty, state: _StatefulBuilderState#24c5a)

Ian Hickson

unread,
Jun 5, 2018, 1:08:15 PM6/5/18
to 李少杰, Eric Seidel, Flutter Dev, Kris Giesing
What you showed in your earlier email is fine, and will work.

You may be interested in studying how MaterialApp implements it to see a more idiomatic solution, but it's not necessarily better.
--

--
Ian Hickson

😸
Reply all
Reply to author
Forward
0 new messages