Skip to content

Instantly share code, notes, and snippets.

@rydmike
Created September 1, 2019 23:21
Show Gist options
  • Save rydmike/014817f7d19a924e7590ece6463c156e to your computer and use it in GitHub Desktop.
Save rydmike/014817f7d19a924e7590ece6463c156e to your computer and use it in GitHub Desktop.
Demo of Flutter Drawer issue on Android with transparent statusbar, as well as no impact of SafeArea(top: false) on Drawer content
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _transparentAppBar = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
drawer: SafeArea(top: false, child: Drawer(child: TestDrawer())),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Turn on/off transparent app bar'),
Switch(
onChanged: (value) {
setState(() {
_transparentAppBar = value;
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.light.copyWith(
statusBarColor: _transparentAppBar
? Colors.transparent
: Colors.black26));
});
},
value: _transparentAppBar),
Text(
'When you make the statusbar transparent you get a "cleaner" '
'appbar look, similar to iOS design. \n\nWithout it there is a '
'scrim on top of the statusbar area.\n NOTE! When you do this, '
'the statusbar area of the Drawer will unfortunately look even '
'uglier than before.',
textAlign: TextAlign.center,
),
],
),
),
),
);
}
}
class TestDrawer extends StatelessWidget {
const TestDrawer({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: ListView(
shrinkWrap: true,
children: <Widget>[
Container(
height: 150,
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Cannot draw from top in Drawer! Not even with '
'SafeArea(top: false) wrapper. '
'If we could draw from the top, then with '
'transparent statusbar, we would get the background of '
'whatever we put at the top of of the drawer as '
'color/gradient/image in the statusbar area. '
'Then we also need to handle the statusbar '
'padding in the drawer manually.',
style: TextStyle(color: Colors.white),
),
)),
ListTile(leading: Icon(Icons.description), title: Text('Item 1')),
ListTile(leading: Icon(Icons.info), title: Text('Item 2')),
ListTile(leading: Icon(Icons.vpn_key), title: Text('Item 3')),
],
),
);
}
}
@rydmike
Copy link
Author

rydmike commented Sep 2, 2019

Here is the same example, with the above fix applied. It fixes the ugly drawer in the statusbar area and adds the removed statusbar height back in the own layout. Worked great in my tests. Thanks again @rajeshzmoke for the solution.

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Demo Home Page'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  bool _transparentAppBar = false;

  @override
  Widget build(BuildContext context) {
    double _statusBarHeight = MediaQuery.of(context).padding.top;
    print('Statusbar height in app: $_statusBarHeight');
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      drawer: SafeArea(top: false, child: Drawer(child: TestDrawer())),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('Turn on/off transparent app bar'),
              Switch(
                  onChanged: (value) {
                    setState(() {
                      _transparentAppBar = value;
                      SystemChrome.setSystemUIOverlayStyle(
                          SystemUiOverlayStyle.light.copyWith(
                              statusBarColor: _transparentAppBar
                                  ? Colors.transparent
                                  : Colors.black26));
                    });
                  },
                  value: _transparentAppBar),
              Text(
                'When you make the statusbar transparent you get a "cleaner" '
                'appbar look, similar to iOS design. \n\nWithout it there is a '
                'scrim on top of the statusbar area.\n NOTE! When you do this, '
                'the statusbar area of the Drawer will unfortunately look even '
                'uglier than before. Unless...',
                textAlign: TextAlign.center,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    double _statusBarHeight = MediaQuery.of(context).padding.top;
    print('Statusbar height in drawer: $_statusBarHeight');

    return Container(
      child: ListView(
        padding: EdgeInsets.only(top: 0),
        shrinkWrap: true,
        children: <Widget>[
          Container(
              height: 150 + _statusBarHeight,
              color: Colors.blue,
              child: Padding(
                padding: EdgeInsets.fromLTRB(8, 8 + _statusBarHeight, 8, 8),
                child: Text(
                  'Hooray, the ListView padding: EdgeInsets.only(top: 0), '
                  'really solves this issue. Then we just add the height '
                  'of the statusbar to our own top container and to its top '
                  'padding for the same size container as before! ',
                  style: TextStyle(color: Colors.white),
                ),
              )),
          ListTile(leading: Icon(Icons.description), title: Text('Item 1')),
          ListTile(leading: Icon(Icons.info), title: Text('Item 2')),
          ListTile(leading: Icon(Icons.vpn_key), title: Text('Item 3')),
        ],
      ),
    );
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment