Height of the status bar always returns 0
Asked Answered
J

3

9

When calling MediaQuery.of(context).padding.top in the parent widget (ProductsOverviewScreen) the value returned is as expected - 24. But when calling the same property from a nested widget (ProductsGrid) of the parent that we are talking about the value is always 0. Is this normal behavior?


products_overview_screen.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../widgets/app_drawer.dart';
import '../screens/cart_screen.dart';
import '../widgets/products_grid.dart';
import '../widgets/badge.dart';
import '../providers/cart.dart';
import '../providers/products_provider.dart';

enum FilterOptions {
  showAll,
  onlyFavorites,
}

class ProductsOverviewScreen extends StatefulWidget {
  @override
  _ProductsOverviewScreenState createState() => _ProductsOverviewScreenState();
}

class _ProductsOverviewScreenState extends State<ProductsOverviewScreen> {
  bool _showFavorites = false;
  bool _isLoading = false;
  bool _isInit = false;

  @override
  void initState() {
//    Future.delayed(Duration(seconds: 1), () {
//      Provider.of<Products>(context).fetchAndSetProducts();
//    });
    super.initState();
  }

  @override
  void didChangeDependencies() {
    if (!_isInit) {
      setState(() {
        _isLoading = true;
      });
      Provider.of<Products>(context).fetchAndSetProducts().then((_) {
        setState(() {
          _isLoading = false;
        });
      });
    }
    _isInit = true;
    super.didChangeDependencies();
  }

  Future<void> refreshProducts(BuildContext context) async {
    await Provider.of<Products>(context, listen: false).fetchAndSetProducts();
  }

  @override
  Widget build(BuildContext context) {
    final scaffoldKey = GlobalKey();
    final appBar = AppBar(
      title: Text('My Shop'),
      actions: <Widget>[
        Consumer<Cart>(
          builder: (ctx, cart, child) => Badge(
            child: child,
            value: cart.length.toString(),
          ),
          child: IconButton(
            onPressed: () {
              final scaffoldState = scaffoldKey.currentState as ScaffoldState;
              scaffoldState.hideCurrentSnackBar();
              Navigator.of(context).pushNamed(CartScreen.routeName);
            },
            icon: Icon(
              Icons.shopping_cart,
              color: Theme.of(context).accentColor,
            ),
          ),
        ),
        PopupMenuButton(
          onSelected: (FilterOptions selectedValue) {
            setState(() {
              if (selectedValue == FilterOptions.onlyFavorites) {
                _showFavorites = true;
              } else {
                _showFavorites = false;
              }
            });
          },
          icon: Icon(Icons.more_vert),
          itemBuilder: (_) => [
            PopupMenuItem(
                child: Text('Only Favorites'),
                value: FilterOptions.onlyFavorites),
            PopupMenuItem(
              child: Text('Show All'),
              value: FilterOptions.showAll,
            ),
          ],
        ),
      ],
    );

    return Scaffold(
      key: scaffoldKey,
      appBar: appBar,
      drawer: AppDrawer(),
      body: _isLoading
          ? Center(child: CircularProgressIndicator())
          : RefreshIndicator(
              onRefresh: () => refreshProducts(context),
              child: ProductsGrid(_showFavorites, appBar.preferredSize.height),
            ),
    );
  }
}

//56

products_grid.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../providers/products_provider.dart';
import '../widgets/product_item.dart';

class ProductsGrid extends StatelessWidget {
  final bool _showFavorites;
  final double _appBarHeight;

  ProductsGrid(this._showFavorites, this._appBarHeight);

  @override
  Widget build(BuildContext context) {
    final productsData = Provider.of<Products>(context);
    final products =
        _showFavorites ? productsData.favoriteItems : productsData.items;
    final mediaQuery = MediaQuery.of(context);

    return productsData.items.isEmpty
        ? SingleChildScrollView(
            physics: AlwaysScrollableScrollPhysics(),
            child: Container(
              width: mediaQuery.size.width,
              height: mediaQuery.size.height -
                  mediaQuery.padding.top -
                  _appBarHeight,
//              child: Center(
//                child: Text(
//                  'There are no products.',
//                  style: TextStyle(
//                    color: Colors.grey,
//                    fontSize: 16,
//                  ),
//                ),
//              ),
            ),
          )
        : GridView.builder(
            padding: const EdgeInsets.all(15),
            itemCount: products.length,
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              childAspectRatio: 3 / 2,
              crossAxisSpacing: 10,
              mainAxisSpacing: 10,
            ),
            itemBuilder: (ctx, index) => ChangeNotifierProvider.value(
              value: products[index],
              child: ProductItem(),
            ),
          );
  }
}
Jakie answered 16/7, 2020 at 20:46 Comment(0)
E
21

You can copy paste run full code below
You can use MediaQueryData.fromWindow(window).padding.top
code snippet

import 'dart:ui';
...
final statusbarHeight2 = MediaQueryData.fromWindow(window).padding.top;

working demo

enter image description here

full code

import 'package:flutter/material.dart';
import 'dart:ui';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: ProductsOverviewScreen(title: 'Flutter Demo Home Page'),
    );
  }
}

class ProductsOverviewScreen extends StatefulWidget {
  ProductsOverviewScreen({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _ProductsOverviewScreenState createState() => _ProductsOverviewScreenState();
}

class _ProductsOverviewScreenState extends State<ProductsOverviewScreen> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    final statusbarHeight1 = MediaQueryData.fromWindow(window).padding.top;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ProductsGrid(),
            Text(
              '$statusbarHeight1',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class ProductsGrid extends StatelessWidget {
  const ProductsGrid({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final statusbarHeight2 = MediaQueryData.fromWindow(window).padding.top;

    return Text(
      '$statusbarHeight2',
    );
  }
}
Endurance answered 17/7, 2020 at 1:34 Comment(0)
T
8

You can get all information about window using window object that provided by dart:ui. Here an example of finding exact size of status bar;

Firstly add this top of the dart file:

import 'dart:ui';

And use window object to find height of the status bar:

final statusBarHeight = window.padding.top / window.devicePixelRatio;
Tallow answered 16/2, 2022 at 10:27 Comment(1)
window is now deprecated. Use View.of(context) instead.Grados
T
1

In case you want to get the size information without accessing BuildContext/Context you can use the following method:

import dart:ui at the top of your file

import 'dart:ui';

Then do this to get the status bar height

FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first;
final statusBarHeight = view.padding.top / view.devicePixelRatio;
Tears answered 19/4, 2024 at 9:50 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.