How do I remove Flutter IconButton big padding?
Asked Answered
R

15

131

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: () {},
            )
          ],
        ),
      );
    }
}

enter image description here

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:

enter image description here

Making the actual icons smaller doesn't help either, the button is still big:

enter image description here

thanks for the help

Runaway answered 16/5, 2018 at 23:8 Comment(2)
Have you tried making your actual icons larger? It looks like the icon may be centered in, but not filling up, it's space in the icon font glyph.Beersheba
use GestureDetector( onTap: () {}, child: new Icon(Icons.volume_up) )Hormuz
A
31

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.

Allomerism answered 18/5, 2018 at 2:50 Comment(1)
wow, the real answer is hidden deep! Setting the padding & constraints doesn't do anything if you're working with small button sizes -- it still forces this 48px minimum!Sweyn
R
309

Simply pass an empty BoxConstraints to the constraints property and a padding of zero.

IconButton(
    padding: EdgeInsets.zero,
    constraints: BoxConstraints(),
)

You have to pass the empty constraints because, by default, the IconButton widget assumes a minimum size of 48px.

Recommend answered 27/7, 2020 at 3:28 Comment(3)
padding: EdgeInsets.zero, its working but getting error of constraints: BoxConstraints(),Promontory
I had zeroed out the filling, but the information on constraints was more important. thanks.Eiser
I preferred using which was half the space, but enough to not be too tight. padding: const EdgeInsets.all(4.0),Apocarp
C
102

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) ) 
Collier answered 6/5, 2019 at 8:54 Comment(8)
Thanks! This fit in perfectly for me :)Sletten
Perfect ever foundBorstal
InkWell if you are trying to mimic a FlatButtonRattlesnake
the hack with the constraints of the IconButton is really dopeJoettejoey
Use IconButton!Barley
Wrapping IconButton in a Container is not removing the paddingHoggish
The Container with a width did the job for me; thanks!Cohesive
this is not workingSafranine
A
31

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.

Allomerism answered 18/5, 2018 at 2:50 Comment(1)
wow, the real answer is hidden deep! Setting the padding & constraints doesn't do anything if you're working with small button sizes -- it still forces this 48px minimum!Sweyn
V
31

2023 Solution:

IconButton(
  onPressed: () {},
  iconSize: 40.0, // desired size
  padding: EdgeInsets.zero,
  constraints: const BoxConstraints(), // override default min size of 48px
  style: const ButtonStyle(
    tapTargetSize: MaterialTapTargetSize.shrinkWrap, // the '2023' part
  ),
  icon: const Icon(Symbols.arrow_right),
),
Vraisemblance answered 14/10, 2023 at 20:39 Comment(1)
i still have small splash, i remove it by add overlayColor: MaterialStateProperty.all(Colors.transparent) in ButtonStyle. Information from hereValenba
B
15

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 : () {},
            ),
        ),
    )
Bengali answered 22/11, 2019 at 13:29 Comment(1)
Nice solution, and it made me aware of the ClipRRect widget and family. :)Steamroller
M
5

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.

Modigliani answered 28/3, 2020 at 11:38 Comment(0)
G
3

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();
    });
Gothenburg answered 19/5, 2020 at 20:3 Comment(0)
H
1

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!

Hypocaust answered 28/8, 2019 at 14:35 Comment(0)
C
0

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: () {}),
 )
Cynthla answered 29/2, 2020 at 11:19 Comment(0)
H
0

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),
         ),
Honan answered 12/12, 2020 at 14:2 Comment(0)
S
0

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

Snorkel answered 13/2, 2023 at 14:31 Comment(0)
P
0

This worked for me

Container(
                      width: 30,
                      child: IconButton(
                        padding: EdgeInsets.zero,
                      ),
                    ),
Precocious answered 11/12, 2023 at 9:6 Comment(0)
T
0
IconButton(
   iconSize: 30,
   padding: EdgeInsets.zero, // make it zero
   constraints: const BoxConstraints(), // make box constraints empty
   style: const ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap), // And this sstyle
   onPressed: () {},
   icon: const Icon(Icons.ac_unit_rounded),
)
Transcendence answered 11/3, 2024 at 8:2 Comment(0)
S
-1

Incase like me you came looking for an answer to the solution of an image instead of just an icon, I tried a mix of solutions here and arrived at a solution - 2024.

You need "tapTargetSize" of shrinkwrap to your IconButton style, need to also add the "padding" of zero and an empty "constraints". Then you need to define your icon image width and height, should you still need a smaller padding, wrap the button with a container and add the a padding to it.

Container(
 padding: EdgeInsets.all(5),
 decoration: BoxDecoration(
   borderRadius: BorderRadius.circular(100)),
  child: IconButton(
    style: ButtonStyle(
    //This shrinks the auto padding
    tapTargetSize: MaterialTapTargetSize.shrinkWrap, 
    ),
    padding: EdgeInsets.zero,
    constraints: BoxConstraints(),
    onPressed: () {},
    icon: Image(
     width: 40,
     height: 40,
     image: AssetImage('your image link here'),
     ),
   ),
 ),

Sanfred answered 24/1, 2024 at 7:54 Comment(0)
C
-9

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: ...,
)
Completion answered 6/9, 2019 at 11:41 Comment(2)
Nowhere in the question it is asked to show ripple effect!Perpend
@Ashish, IconButton implies having ripple effect. If you don't need ripple effect, you can just use GestureDetector. It's quite simple and shown in the top answer. My solution allows to remove padding but keep IconButton-like rippleCompletion

© 2022 - 2025 — McMap. All rights reserved.