Flutter: IconButton() Being Partially Rendered Outside It's Container() - flutter

I'm trying to up my game when it comes to my Flutter layout / sizing knowledge and this post is something that I recently observed that confuses me.
I have a Container() that has an IconButton() having an icon from the stock Flutter icon set with a size that is passed as a parameter to the function.
Here is the code:
Widget buttonGallery(double size) {
return Container(
color: Colors.yellow,
child: IconButton(
icon: Icon(
Icons.photo,
size: size,
color: Colors.blue,
),
onPressed: (){},
},
),
);
}
With the size set to 75, I am noticing that the IconButton() is being partially rendered outside of its parent Container(). (This behavior is visible as I explicitly set the Container() color to yellow to be able to see the parent client area). See pic below:
Here are my questions:
Isn't the parent widget, which in this is a Container(), supposed to envelop it's child widget meaning that the child shouldn't overflow outside of it's parent? (I know that there's the OverflowBox() widget that supposed to allow this behavior, but I don't think that's the case here.)
In the case where the child is too big to fit its parent's client area, isn't Flutter supposed to clip the child and show those yellow hazzard lines indicating this scenario?
Having dealt a lot with Container(), I was under the impression that it was supposed to fit itself to the dimensions of its child. I'm confused why it's not doing this now.
All help/suggestions greatly appreciated.
/Joselito

The IconButton widget sizes itself according to the property iconSize. It defaults to 24, and that's the size being passed to your container.
This should do it for you:
Widget buttonGallery(double size) {
return Container(
color: Colors.yellow,
child: IconButton(
iconSize: size,
icon: Icon(
Icons.photo,
size: size,
color: Colors.blue,
),
onPressed: (){},
},
),
);
}

Related

How can I adjust flutter icon button (or image button) to get larger?

leading: Padding(
padding: EdgeInsets.only(left: 20),
child: IconButton(
onPressed: () => print('Menu Tapped'),
icon: Image.asset(
'assets/images/vecteezy_triangle_1200693.png',
fit: BoxFit.fitWidth,
),
),
),
I try adding height: and width: to the Image.asset and iconsize: to IconButton but it does't work
Does it have something to do with edgeInsets?
PS* I'm quite new here, I'm follow YouTube to write a financial management app
if your code is about Appbar you need to increase the icon's space in the Appbar by using toolbarHeight: and leadingWidth: in the Appbar widget.
I hope this work for you.
Since you are providing this widget to "leading", I'm guessing this is for an AppBar. The size of the icon cannot exceed the size of your appbar. You need to increase the size of your appbar to be able to increase the size of your icon. If this doesn't work, provide your code containing the AppBar widget so I can test it out for you.

ListTile covers button animation

Just noticed that ListTile cover button animation when wrapped inside a container with background color set to anything but transparent. Wrapping ListTile in a container with set color is the only way I know to change background color of ListTile. Is there any other way to change background color of the ListTile without loosing button animation?
Container(
color: Colors.green,
child: ListTile(
title: Text('Test'),
trailing: IconButton(
icon: Icon(Icons.add),
onPressed: () {},
),
),
)
OUTPUT
This is because of the way InkWell works (Some buttons, like the IconButton, use InkWell or InkResponse as their parent). You can read about it more on this github issue page.
In order to make that ripple effect to display on top of the decorated Container (the green one in your code) - it needs a Material widget above the Container in the widget display tree.
So you should edit the code and add a Material widget with transparency in your Container, so the widget display tree will look like Container -> Material -> Ink.
Container(
color: Colors.green,
child: Material(
type: MaterialType.transparency,
child: ListTile(
title: Text('Test'),
trailing: IconButton(
icon: Icon(Icons.add),
onPressed: () {},
),
),
),
),

How to scale Chip layout box along with Chip inside Wrap in Flutter

Inside a Wrap I have an array of StatelessWidget representing tags. Right now, the child widget simply returns a Chip. The build method for my Tag widget looks like:
Widget build(BuildContext context) {
return Chip(
label: Text('#the-tag-name'));
}
The Chips render like so:
I'd like to render smaller chips, so following the advice here, I've updated it to this:
Widget build(BuildContext context) {
return Transform(
transform: Matrix4.identity()..scale(0.8),
child: Chip(
label: Text('#the-tag-name')),
);
}
This is the result:
I'd like to retain the initial spacing between the Chips, but it seems that the transform isn't transforming the original layout size of the Chip:
The debug paint shows additional non-scaled padding to the right and bottom of each chip. Is there any way to remove this?
My advice would be to stay away from using Transform. It can lead to unintended consequences.
The reason your Chip padding won't go any smaller is because it is restricted by Material specifications. A clickable widget has a minimum tapTarget size. You can test this out by looking at the materialTapTargetSize on your chip.
CMD+click on the shringWrap and you will see that it says: "Shrinks the tap target size to the minimum provided by the Material specification."
Chip(
label: Text('#the-tag-name',
style: TextStyle(fontSize: 10.0)),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
So if you really need to shrink your widget, your best bet is to go another route. Possibly by using a RawMaterialButton like this: The padding and textSize can be adjusted as needed.
RawMaterialButton(
onPressed: () {},
constraints: BoxConstraints(),
padding: EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
child: Text(
'#the-tag-name',
style: new TextStyle(fontSize: 12.0),
),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(18.0),
),
fillColor: Colors.grey[300],
),

What is the alternative to IntrinsicHeight in flutter?

I have this code in bottomNavigationBar"
bottomNavigationBar: BottomAppBar(
child: IntrinsicHeight(
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.of(context).pop(),
),
Spacer(),
IconButton(
icon: Text(
"QR",
style: Theme.of(context).textTheme.title,
),
onPressed: () => Navigator.of(context).pop(),
),
VerticalDivider(
color: Theme.of(context).textTheme.headline.color,
),
IconButton(
icon: Icon(Icons.share),
onPressed: () => Navigator.of(context).pop(),
),
],
),
),
),
And the code works as expected.
If I remove IntrinsicHeight widget, the divider goes all the way across all screen.
The reason I want an alternative is because in the documentation of IntrinsicHeight it says:
This class is relatively expensive. Avoid using it where possible.
What would be the cheap alternative?
Thank you
If you're looking for "a cheap way to have the row fit the min height of dynamic content", then there are none.
The cheap solution is, to have a fixed height on the Row – typically by wrapping it in SizedBox:
SizedBox(
height: 42,
child: Row(...),
)
This works well if the content has a fixed height. But it won't if the height is dynamic.
In this specific case, you could either use SizedBox with height=48 (this is the default height of the IconButton widget) or avoid using VerticalDivider and draw it by adding a left border to the share icon.
Container(
decoration: BoxDecoration(
border: Border(
left: Divider.createBorderSide(
context,
color: Theme.of(context).textTheme.headline.color,
),
),
),
child: IconButton(
icon: Icon(Icons.share),
onPressed: () => Navigator.of(context).pop(),
),
),
In Flutter it might seem counter-intuitive, but when most widgets are given bounded constraints they try to fill the whole (bounded) space allowed, whereas when given unbounded constraints (set to INFINITY) they only take the required space (their intrinsic size). So to make a widget have its intrinsic size one can try wrapping it with UnconstrainedBox.
But it might be problematic in your case, because you are using a Row, and its height should not be unbounded..
Wrap a widget in a Container with a specific height that's the alternative of Intrinsic Height.

How do I remove Flutter IconButton big padding?

I want to have a row of IconButtons, all next to each other, but there seems to be pretty big padding between the actual icon, and the IconButton limits. I've already set the padding on the button to 0.
This is my component, pretty straightforward:
class ActionButtons extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.lightBlue,
margin: const EdgeInsets.all(0.0),
padding: const EdgeInsets.all(0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
IconButton(
icon: new Icon(ScanrIcons.reg),
alignment: Alignment.center,
padding: new EdgeInsets.all(0.0),
onPressed: () {},
),
IconButton(
icon: new Icon(Icons.volume_up),
alignment: Alignment.center,
padding: new EdgeInsets.all(0.0),
onPressed: () {},
)
],
),
);
}
}
I want to get rid of most of the light blue space, have my icons start earlier on the left, and closer to each other, but I can't find the way to resize the IconButton itself.
I'm almost sure this space is taken by the button itself, 'cause if I change their alignments to centerRight and centerLeft they look like this:
Making the actual icons smaller doesn't help either, the button is still big:
thanks for the help
Simply pass an empty BoxConstrains to the constraints property and a padding of zero.
IconButton(
padding: EdgeInsets.zero,
constraints: BoxConstraints(),
)
You have to pass the empty constrains because, by default, the IconButton widget assumes a minimum size of 48px.
Two ways to workaround this issue.
Still Use IconButton
Wrap the IconButton inside a Container which has a width.
For example:
Container(
padding: const EdgeInsets.all(0.0),
width: 30.0, // you can adjust the width as you need
child: IconButton(
),
),
Use GestureDetector instead of IconButton
You can also use GestureDetector instead of IconButton, recommended by Shyju Madathil.
GestureDetector( onTap: () {}, child: Icon(Icons.volume_up) )
It's not so much that there's a padding there. IconButton is a Material Design widget which follows the spec that tappable objects need to be at least 48px on each side. You can click into the IconButton implementation from any IDEs.
You can also semi-trivially take the icon_button.dart source-code and make your own IconButton that doesn't follow the Material Design specs since the whole file is just composing other widgets and is just 200 lines that are mostly comments.
Wrapping the IconButton in a container simply wont work, instead use ClipRRect and add a material Widget with an Inkwell, just make sure to give the ClipRRect widget enough border Radius 😉.
ClipRRect(
borderRadius: BorderRadius.circular(50),
child : Material(
child : InkWell(
child : Padding(
padding : const EdgeInsets.all(5),
child : Icon(
Icons.favorite_border,
),
),
onTap : () {},
),
),
)
Instead of removing a padding around an IconButton you could simply use an Icon and wrap it with a GestureDetector or InkWell as
GestureDetector(
ontap:(){}
child:Icon(...)
);
Incase you want the ripple/Ink splash effect as the IconButton provides on click wrap it with an InkWell
InkWell(
splashColor: Colors.red,
child:Icon(...)
ontap:(){}
)
though the Ink thrown on the Icon in second approach wont be so accurate as for the IconButton, you may need to do some custom implementation for that.
Here's a solution to get rid of any extra padding, using InkWell in place of IconButton:
Widget backButtonContainer = InkWell(
child: Container(
child: const Icon(
Icons.arrow_upward,
color: Colors.white,
size: 35.0,
),
),
onTap: () {
Navigator.of(_context).pop();
});
I was facing a similar issue trying to render an Icon at the location the user touches the screen. Unfortunately, the Icon class wraps your chosen icon in a SizedBox.
Reading a little of the Icon class source it turns out that each Icon can be treated as text:
Widget iconWidget = RichText(
overflow: TextOverflow.visible,
textDirection: textDirection,
text: TextSpan(
text: String.fromCharCode(icon.codePoint),
style: TextStyle(
inherit: false,
color: iconColor,
fontSize: iconSize,
fontFamily: icon.fontFamily,
package: icon.fontPackage,
),
),
);
So, for instance, if I want to render Icons.details to indicate where my user just pointed, without any margin, I can do something like this:
Widget _pointer = Text(
String.fromCharCode(Icons.details.codePoint),
style: TextStyle(
fontFamily: Icons.details.fontFamily,
package: Icons.details.fontPackage,
fontSize: 24.0,
color: Colors.black
),
);
Dart/Flutter source code is remarkably approachable, I highly recommend digging in a little!
A better solution is to use Transform.scale like this:
Transform.scale(
scale: 0.5, // set your value here
child: IconButton(icon: Icon(Icons.smartphone), onPressed: () {}),
)
You can use ListTile it gives you a default space between text and Icons that would fit your needs
ListTile(
leading: Icon(Icons.add), //Here Is The Icon You Want To Use
title: Text('GFG title',textScaleFactor: 1.5,), //Here Is The Text Also
trailing: Icon(Icons.done),
),
I like the following way:
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () {},
child: Container(
padding: const EdgeInsets.all(8),
child: const Icon(Icons.favorite, color: Colors.red),
),
),
enter image description here
To show splash effect (ripple), use InkResponse:
InkResponse(
Icon(Icons.volume_up),
onTap: ...,
)
If needed, change icons size or add padding:
InkResponse(
child: Padding(
padding: ...,
child: Icon(Icons.volume_up, size: ...),
),
onTap: ...,
)