How to remove Padding from DrawerHeader - flutter

Here's my DrawerHeader :
class MyDrawerHeader extends StatefulWidget {
#override
_MyDrawerHeaderState createState() => _MyDrawerHeaderState();
}
class _MyDrawerHeaderState extends State<MyDrawerHeader> {
#override
Widget build(BuildContext context) {
return DrawerHeader(
padding: EdgeInsets.all(0),
margin: EdgeInsets.all(0),
child: Center(child: Text('Header', style: Theme.of(context).textTheme.headline))
);
}
}
As you can see I made the Padding and Margin from the DrawerHeader be 0, but this is how my Header is being shown:
It's just too big and I can't make it smaller. I have no idea why its being rendered this way, I looked into DrawerHeader source code and I can't see anything in there overriding my Padding or Margin.
Just to be sure the problem is in DrawerHeader, this is what Happens when I substitute it for a Container:
It works as it should!
Am I missing something, or is this a bug in Flutter?

drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
padding: EdgeInsets.all(0.0),
child: Container(
color: Theme.of(context).primaryColor,
),
),
ListTile(
title: Text("Home"),
)
],
),
),

There is always padding on DrawerHeader. If you look in sources:
#override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
assert(debugCheckHasMediaQuery(context));
final ThemeData theme = Theme.of(context);
final double statusBarHeight = MediaQuery.of(context).padding.top;
return Container(
height: statusBarHeight + _kDrawerHeaderHeight,
margin: margin,
decoration: BoxDecoration(
border: Border(
bottom: Divider.createBorderSide(context),
),
),
child: AnimatedContainer(
padding: padding.add(EdgeInsets.only(top: statusBarHeight)),
decoration: decoration,
duration: duration,
curve: curve,
child: child == null ? null : DefaultTextStyle(
style: theme.textTheme.body2,
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: child,
),
),
),
);
}
You can customize this code:
height: statusBarHeight + _kDrawerHeaderHeight - here is total height of header
padding: padding.add(EdgeInsets.only(top: statusBarHeight)) - here is padding of child element in DrawerHeader

Try replacing your drawer by the code below
drawer: Drawer(
child: DrawerHeader(
child: ListView(
children: <Widget>[
Container(
alignment: Alignment.topLeft,
child: Text('Header', style: Theme.of(context).textTheme.headline),
),
],
),
),
),

Related

How to remove padding of MaterialBanner?

I want to remove the following blue padding from MaterialBanner widget, but it doesn't seem to be customizable. I want to insert an image in the red region.
I looked into MaterialBanner for using across Scaffold widgets because ScaffoldMessenger doesn't allow me to insert widgets other than MaterialBanner.
Is there any suggestion?
dartpad.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Scaffold(body: JustBanner())));
}
class JustBanner extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _JustBannerState();
}
}
class _JustBannerState extends State<JustBanner> {
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
final messenger = ScaffoldMessenger.of(context);
messenger.clearMaterialBanners();
messenger.showMaterialBanner(MaterialBanner(
padding: EdgeInsets.zero,
leadingPadding: EdgeInsets.zero,
leading: const SizedBox.shrink(),
backgroundColor: Colors.blue,
content: Container(
color: Colors.red,
width: 200,
height: 50,
),
actions: const [SizedBox.shrink()]));
},
child: const Text('Banner')),
],
);
}
}
Container(
width: MediaQuery.of(context).size.width,
child: MaterialBanner(
content: Text('Hello'),
actions: [
Icon(Icons.add),
],
),
),
Its no possible without copy and re-create the class, buttonBar always appear:
final Widget buttonBar = Container( // <-- problematic widget
alignment: AlignmentDirectional.centerEnd,
constraints: const BoxConstraints(minHeight: 52.0),
padding: const EdgeInsets.symmetric(horizontal: 8),
child: OverflowBar(
overflowAlignment: widget.overflowAlignment,
spacing: 8,
children: widget.actions,
),
);
final double elevation = widget.elevation ?? bannerTheme.elevation ?? 0.0;
final Color backgroundColor = widget.backgroundColor
?? bannerTheme.backgroundColor
?? theme.colorScheme.surface;
final TextStyle? textStyle = widget.contentTextStyle
?? bannerTheme.contentTextStyle
?? theme.textTheme.bodyText2;
Widget materialBanner = Container(
margin: EdgeInsets.only(bottom: elevation > 0 ? 10.0 : 0.0),
child: Material(
elevation: elevation,
color: backgroundColor,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: padding,
child: Row(
children: <Widget>[
if (widget.leading != null)
Padding(
padding: leadingPadding,
child: widget.leading,
),
Expanded(
child: DefaultTextStyle(
style: textStyle!,
child: widget.content,
),
),
if (isSingleRow)
buttonBar, // <----- here
],
),
),
if (!isSingleRow)
buttonBar, // <----- here
if (elevation == 0)
const Divider(height: 0),
],
),
),
);

How to get the status bar height when SystemUiMode is defined to hide the status bar?

I'm overlaying my SystemUiMode, the code is below:
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
I need this SystemUiMode.
Well i have widgets within a SingleChildScrollView (a form let's say). When the keyboard shows up and my content inside the ScrollView is big enough to fill all the available space it hits the top margin of the screen. I wanted a design where my SingleChildScroview had a top padding of the same size of the status bar.
I tried:
To use SafeArea: but it doesn't work, in a first moment my widget fill the entire available space ignoring the status bar height, then it flickers between the expected layout and then goes to filled again. Below is the code:
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
return SafeArea(
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: SingleChildScrollView(
child: Center(
child: Container(
width: size.width * .8,
height: size.height * .9,
color: Colors.red,
child: Center(child: TextField()),
),
),
),
),
),
);
}
}
I tried to listen to the changes of the MediaQuery and store the value of the height, but when the keyboard shows up for the first time (sometimes in a second too) it fills the entire space available.
static double topPadding = 0;
setTopPadding(double newPad) {
if (newPad > topPadding) topPadding = newPad;
}
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
setTopPadding(MediaQuery.of(context).viewPadding.top);
return Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Padding(
padding: EdgeInsets.only(top: topPadding),
child: SingleChildScrollView(
child: Center(
child: Container(
width: size.width * .8,
height: size.height * .9,
color: Colors.red,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text("A"),
TextField(),
Text("B"),
TextField(),
],
)),
),
),
),
),
);
}
What's the way to get the static height of the status bar?
you can the give Colors.transparent to statusBarColor of the systemOverlayStyle
that makes the statusBar disappear
better to use CustomScrollView Widget instead of SingleChildScrollView...
CustomScrollView(
physics: const BouncingScrollPhysics(), slivers: [
SliverAppBar(
systemOverlayStyle:
const SystemUiOverlayStyle(statusBarColor: Colors.transparent ),
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: 'hello',
background: NetworkImage(imageUrl: networkImage),
),
),
SliverList(
delegate: SliverChildListDelegate(
[
Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(30),
topLeft: Radius.circular(30))),
padding: const EdgeInsets.symmetric(horizontal: 14.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getScreenHeight(10)),
Text(
name,
maxLines: 1,
style: Theme.of(context).textTheme.subtitle1,
textAlign: TextAlign.start,
),]
),)
]);
),
),
},

Center the trailing icon of expansion tile in Flutter

I would like to horizontally center the trailing icon of my expansionTile,
Here is my expansionTile with the trailing on the bottom right :
I already tried to encapsulate the Icon in a Align and a Container but doesn't work, I also tried Padding but it's not stable if you change the size of the screen.
Code with Align :
trailing : Align(
alignment: Alignment.center,
child: Icon(
BeoticIcons.clock,
color: BeoColors.lightGreyBlue
)
),
With Container :
trailing: Container(
alignment: Alignment.center,
child: Icon(
BeoticIcons.clock,
color: BeoColors.lightGreyBlue
)
),
Thanks for your help.
This will work for you. Use LayoutBuilder to get parent widget width, and set relative padding using constraints. For example, use constraints.maxWidth * 0.5, to center across width. Your padding will be stable if you change the size of the screen:)
trailing: LayoutBuilder(builder: (ctx, constraints) {
return Padding(
padding: EdgeInsets.only(
right: constraints.maxWidth * 0.5,
),
child: Icon(
Icons.menu,
),
);
}),
you can use column and align your icon like this way hope this code will help you, thank you
import 'package:flutter/material.dart';
class Hello extends StatelessWidget {
const Hello({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 140,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
color: Colors.deepPurple[200],
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Center(child: Text("Hello")),
Text("Hello"),
SizedBox(height: 50,),
Align(
alignment: Alignment.center,
child: Icon(Icons.lock_clock))
],
),
),
),
),
),
);
}
}
Ok, I found how to do it.
Simply put the icon in the title attribute of the ExpansionTile :
return ExpansionTile(
title: Icon(
BeoticIcons.simply_down,
color: BeoColors.lightGreyBlue,
),

Flutter ListView not scrolling (I feel like I've tried every solution on the internet)

If I drag and hold my finger down I can see a few items that are below the cutoff of the screen but as soon as I let go, it just bounces back to the top. I tried using SingleChildScrollView places, tried setting primary = true, and a bunch of other stuff that didn't help. I'm fairly new to flutter so any help would be appreciated!! Let me know if any more info is needed.
Here is my code:
import 'package:flutter/material.dart';
import 'package:drink_specials/models/restaurant.dart';
import 'package:drink_specials/screens/home/restaurant_list.dart';
class RestaurantNameTextStyle {
static TextStyle display5(BuildContext context) {
return Theme.of(context).textTheme.headline2.copyWith(color: Colors.white);
}
}
class RestaurantTypeTextStyle {
static TextStyle display5(BuildContext context) {
return Theme.of(context).textTheme.headline6.copyWith(color: Colors.white);
}
}
class RestaurantDetail extends StatelessWidget {
final Restaurant restaurant;
RestaurantDetail({Key key, #required this.restaurant}) : super(key: key);
#override
Widget build(BuildContext context) {
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 100.0),
Text(
restaurant.name,
style: RestaurantNameTextStyle.display5(context),
),
SizedBox(height: 10.0),
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
restaurant.restaurant_type,
style: RestaurantTypeTextStyle.display5(context),
))),
],
);
final topContent = Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10.0),
height: MediaQuery.of(context).size.height * 0.5,
decoration: new BoxDecoration(
image: new DecorationImage(
image: NetworkImage(restaurant.photo),
fit: BoxFit.cover,
),
)),
Container(
height: MediaQuery.of(context).size.height * 0.5,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: Center(
child: topContentText,
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(8.0),
child: Center(
child: ListView.builder(
scrollDirection: Axis.vertical,
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
itemCount: restaurant.specials.length,
itemBuilder: (context, index) {
final item = restaurant.specials[index];
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, 1.0)),
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal:20, vertical:10),
title: Text(item, style: TextStyle(color: Colors.white)),
)
),
);
}
),
),
);
return Scaffold(
body: Column(
children: <Widget>[
topContent,
Expanded(
child: bottomContent,
),
],
),
);
}
}
There is a ListView inside a SingleChildScrollView and both of them are scrollable. Scrolling on one of them should be disabled.
As they already explained. If you have a ListView.builder, you don't need SingleChildScrollView.
Try removing SingleChildScrollView. The code should look like this:
Scaffold(
body: Column(
children: <Widget>[
topContent,
Expanded(
child: bottomContent,
),
],
),
);
ListView already have scroll behavior so you won't need some SingleChildScrollView

How to prevent Row from taking all available width?

I have one problem with my CustomChip :
I need to wrap the card to fit the content only.
However, I have a second requirement: The long text should overflow fade.
When I fixed the second problem, this issue started to occur when I added Expanded to wrap the inner Row
I don't understand why the inner Row also seems to expand although its mainAxisSize is already set to min
Here is the code:
The screen:
import 'package:flutter/material.dart';
import 'package:app/common/custom_chip.dart';
class RowInsideExpanded extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1.0,
),
),
width: 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildChip('short'),
_buildChip('looooooooooooooooooooooongg'),
],
),
),
),
);
}
_buildChip(String s) {
return Row(
children: [
Container(
color: Colors.red,
width: 15,
height: 15,
),
Expanded(
child: CustomChip(
elevation: 0.0,
trailing: Container(
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
),
child: Icon(Icons.close),
),
onTap: () {},
height: 42.0,
backgroundColor: Colors.black12,
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
s,
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16.0),
),
),
),
),
],
);
}
}
And the CustomChip
import 'package:flutter/material.dart';
class CustomChip extends StatelessWidget {
final Widget leading;
final Widget trailing;
final Widget title;
final double height;
final double elevation;
final Color backgroundColor;
final VoidCallback onTap;
const CustomChip({
Key key,
this.leading,
this.trailing,
this.title,
this.backgroundColor,
this.height: 30.0,
this.elevation = 2.0,
this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Card(
elevation: elevation,
color: backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
child: InkWell(
onTap: onTap,
child: Container(
height: height,
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
leading ?? Container(),
SizedBox(
width: 5.0,
),
Flexible(
child: title,
fit: FlexFit.loose,
),
SizedBox(
width: 5.0,
),
trailing ?? Container(),
],
),
),
),
),
);
}
}
Look for "MainAxisSize" property and set to "MainAxisSize.min"
Instead of Expanded, just replace it with a Flexible that's because Expanded inherits Flexible but set the fit proprety to FlexFit.tight
When fit is FlexFit.tight, the box contraints for any Flex widget descendant of a Flexible will get the same box contraints. That's why your Row still expands even though you already set its MainAxisSize to min.
I changed your code to print the box contraints using a the LayoutBuilder widget.
Consider your code with Expanded:
import 'package:flutter/material.dart';
class RowInsideExpanded extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1.0,
),
),
width: 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildChip('short'),
SizedBox(
height: 5,
),
_buildChip('looooooooooooooooooooooongg'),
],
),
),
),
);
}
_buildChip(String s) {
return Row(
children: [
Container(
color: Colors.red,
width: 15,
height: 15,
),
Expanded(
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
print("outter $constraints");
return Container(
color: Colors.greenAccent,
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
print("inner $constraints");
return Row(
mainAxisSize: MainAxisSize.min, // this is ignored
children: <Widget>[
SizedBox(
width: 5.0,
),
Flexible(
fit: FlexFit.loose,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
s,
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16.0),
),
),
),
SizedBox(
width: 5.0,
),
Container(
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
),
child: Icon(Icons.close),
),
],
);
}),
);
}),
),
],
);
}
}
It prints
I/flutter ( 7075): outter BoxConstraints(w=183.0, 0.0<=h<=Infinity)
I/flutter ( 7075): inner BoxConstraints(w=183.0, 0.0<=h<=Infinity)
(Look at the width in w, it constrained to be 183.0 for both outter and inner Row)
Now I changed the Expanded to Flexible and check the logs:
I/flutter ( 7075): outter BoxConstraints(0.0<=w<=183.0, 0.0<=h<=Infinity)
I/flutter ( 7075): inner BoxConstraints(0.0<=w<=183.0, 0.0<=h<=Infinity)
(Look at the width in w, it constrained to between zero and 183.0 for both outter and inner Row)
Now your widget is fixed: