Как мне удалить Flutter IconButton большой отступ?

Я хочу иметь ряд значков IconButton, расположенных рядом друг с другом, но между реальной иконкой и пределами IconButton, похоже, имеется довольно большой отступ. Я уже установил отступ для кнопки на 0.

Это мой компонент, довольно простой:

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

Я хочу избавиться от большей части светло-синего пространства, чтобы мои иконки начинались раньше слева и были ближе друг к другу, но я не могу найти способ изменить размер самой IconButton.

Я почти уверен, что это место занято самой кнопкой, потому что если я изменю их выравнивание на centerRight а также centerLeft они выглядят так:

Уменьшение фактических значков также не помогает, кнопка все еще большая:

Спасибо за помощь

13 ответов

Решение

Это не так много, что там есть прокладка. IconButton - это виджет Material Design, который следует спецификации, согласно которой объекты, которые должны быть вставлены, должны иметь размер не менее 48 пикселей с каждой стороны. Вы можете нажать на реализацию IconButton из любых IDE.

Вы также можете тривиально взять исходный код icon_button.dart и создать свой собственный IconButton, который не соответствует спецификациям Material Design, поскольку весь файл состоит только из других виджетов и содержит всего 200 строк, которые в основном являются комментариями.

Просто передайте пустой BoxConstrains к constraints свойство и нулевое заполнение.

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

Вы должны передать пустые ограничения, потому что по умолчанию виджет IconButton принимает минимальный размер 48 пикселей.

Два способа обойти эту проблему.

Все еще используйте IconButton

Оберните IconButton внутри контейнера, который имеет ширину.

Например:

Container(
  padding: const EdgeInsets.all(0.0),
  width: 30.0, // you can adjust the width as you need
  child: IconButton(
  ),
),

Используйте GestureDetector вместо IconButton

Вы также можете использовать GestureDetector вместо IconButton, рекомендованного Shyju Madathil.

GestureDetector( onTap: () {}, child: Icon(Icons.volume_up) ) 

2023 Решение:

      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),
),

Обертывание IconButtonв контейнере просто не будет работать, вместо этого используйте ClipRRect и добавьте виджет материала с чернильницей, просто убедитесь, чтоClipRRect Виджет достаточно радиуса границы.

ClipRRect(
    borderRadius: BorderRadius.circular(50),
    child : Material(
        child : InkWell(
            child : Padding(
                padding : const EdgeInsets.all(5),
                child : Icon(
                    Icons.favorite_border,
                    ),
                ),
            onTap : () {},
            ),
        ),
    )

Вместо удаления отступа вокруг IconButton вы можете просто использовать Icon и обернуть его GestureDetector или InkWell как

GestureDetector(
   ontap:(){}
   child:Icon(...)
);

Если вы хотите, чтобы эффект пульсации / всплеска чернил, как IconButton, при нажатии, оберните его с помощью InkWell

InkWell(
   splashColor: Colors.red,
   child:Icon(...)
   ontap:(){}
)

хотя чернила, нанесенные на значок во втором подходе, не будут такими точными, как для IconButton, вам может потребоваться выполнить некоторую индивидуальную реализацию для этого.

Вот решение, чтобы избавиться от лишних отступов, используя InkWell на месте IconButton:

Widget backButtonContainer = InkWell(
    child: Container(
      child: const Icon(
        Icons.arrow_upward,
        color: Colors.white,
        size: 35.0,
      ),
    ),
    onTap: () {
      Navigator.of(_context).pop();
    });

Я столкнулся с аналогичной проблемой, пытаясь отобразить значок в том месте, где пользователь касается экрана. К сожалению, Icon класс оборачивает выбранную вами иконку в SizedBox,

Читая немного исходного кода класса Icon, получается, что каждый Icon может рассматриваться как текст:

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,
        ),
      ),
    );

Так, например, если я хочу сделать Icons.details чтобы указать, куда мой пользователь только что указал, безо всякого поля, я могу сделать что-то вроде этого:

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 замечательно доступен, я очень рекомендую покопаться в нем немного!

Мне нравится следующий способ:

      InkWell(
  borderRadius: BorderRadius.circular(50),
  onTap: () {},
  child: Container(
    padding: const EdgeInsets.all(8),
    child: const Icon(Icons.favorite, color: Colors.red),
  ),
),

введите описание изображения здесь

Вы можете использовать ListTile, он дает вам пространство по умолчанию между текстом и значками, которое соответствует вашим потребностям.

      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),
         ),

Лучшее решение - использовать Transform.scale как это:

 Transform.scale(
   scale: 0.5, // set your value here
   child: IconButton(icon: Icon(Icons.smartphone), onPressed: () {}),
 )
       GestureDetector(
   onTap: () {
    Navigator.pop(context);
     },
    child: const Icon(Icons.arrow_back_ios),
  ),

Чтобы показать эффект всплеска (рябь), используйте InkResponse:

InkResponse(
  Icon(Icons.volume_up),
  onTap: ...,
)

При необходимости измените размер значков или добавьте отступ:

InkResponse(
  child: Padding(
    padding: ...,
    child: Icon(Icons.volume_up, size: ...),
  ),
  onTap: ...,
)
Другие вопросы по тегам