Стек кнопок Flutter — Значок должен перекрывать родительский

#flutter #button #stack #overlap

Вопрос:

У меня есть кнопка, для которой требуется, чтобы значок располагался немного за пределами прямоугольника.

Я могу сделать это нормально со стеком, однако граница кнопки перекрывает значок, как вы можете видеть здесь:

снимок экрана кнопки

Это должно выглядеть так: отредактированное изображение кнопки

вот мой код:

 OutlinedButton(
                style: scansButtonStyle,
                onPressed: () {}, // TODO: add later
                child: Stack(clipBehavior: Clip.none, children: [
                  Padding(
                    padding: const EdgeInsets.only(left: 50.0),
                    child: Text('CONNECT'),
                  ),
                  Positioned(
                    bottom: 0,
                    left: -20,
                    child: CircleAvatar(
                      radius: 30,
                      backgroundColor: Colors.black,
                      child: CircleAvatar(
                        radius: 27,
                        backgroundColor: Colors.white,
                        child: Icon(
                          Icons.bluetooth_connected,
                          color: Colors.black,
                          size: 48,
                        ),
                      ),
                    ),
                  ),
                ]),
              ),
 

и укладка:

 final ButtonStyle scansButtonStyle = OutlinedButton.styleFrom(
    alignment: Alignment.centerLeft,
    primary: Colors.black,
    backgroundColor: Color(0xfffcd722),
    minimumSize: Size(242, 48),
    padding: EdgeInsets.fromLTRB(20, 3, 20, 3),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.only(
          topLeft: Radius.circular(16),
          topRight: Radius.zero,
          bottomRight: Radius.circular(16),
          bottomLeft: Radius.zero),
    ),
    textStyle: const TextStyle(
      color: Colors.black,
      fontWeight: FontWeight.w600,
      fontSize: 34,
      fontFamily: 'HP',
    ),
    side: BorderSide(
      color: Colors.black,
      width: 3.0,
      style: BorderStyle.solid,
    ));
 

Комментарии:

1. можете поделиться своей ожидаемой картинкой?

2. Я отредактировал его, чтобы включить ожидаемое изображение

Ответ №1:

Я немного исправил код.
Основными изменениями являются:

  1. Поместите описанную кнопку в стопку
  2. Изменил CircleAvatar на простой контейнер с украшением (вам действительно нужен CircleAvatar для этого? Будете ли вы каким-либо образом анимировать иконку? Если нет, то простой контейнер может быть лучше)
  3. Добавьте IgnorePointer к значку, чтобы он игнорировал событие нажатия и передавал его ниже самой кнопке (это для эффекта пульсации даже при нажатии на значок).
  4. Оберните значок виджетом FittedBox и добавьте дополнения во внешний контейнер. Это позволит нашей иконке динамически изменять свой размер в зависимости от размера внешнего круга.
  5. Добавлены некоторые параметры в текстовый виджет, чтобы он не нарушал дизайн, если текст длиннее ширины. Вы можете проверить это с помощью текста(«ПОДКЛЮЧИТЬСЯ» * 10)
 Stack(
                  clipBehavior: Clip.none,
                  children: [
                    OutlinedButton(
                      onPressed: () {},
                      style: scansButtonStyle,
                      child: Padding(
                        padding: const EdgeInsets.only(left: 50.0),
                        child: Text(
                          'CONNECT',
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          textScaleFactor: 1.0, // We do not want OS preferences (text scale option) to break our button's design
                        ),
                      ),
                    ),
                    Positioned(
                      bottom: 0,
                      child: IgnorePointer(
                        //ignore touch events, so that the Outlined button triggers touch animation when pressed on the icon
                        child: SizedBox(
                          width: 60.0,
                          child: AspectRatio(
                            aspectRatio: 1.0,
                            child: Container(
                              padding: EdgeInsets.all(6.0),
                              decoration: BoxDecoration(
                                color: Colors.white,
                                border: Border.all(
                                  color: Colors.black,
                                  width: 3.0,
                                ),
                                shape: BoxShape.circle,
                              ),
                              child: FittedBox(
                                child: Icon(
                                  Icons.bluetooth_connected,
                                  color: Colors.black,
                                ),
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                  ],
                )
 

Код может потребовать некоторых дополнительных корректировок, но вы поймете идею.

Пожалуйста, также обратите внимание, что верхний вырез значка не занимает места (из-за Clip.none и его положения в стеке). Вы можете проверить это, завернув кнопку в цветной контейнер.

Если вам не нравится идея aspectRatio внутри SizedBox — измените его обратно на ширину/высоту в контейнере.

Комментарии:

1. Потрясающе — просто крошечная настройка положения значка, и он выглядит И делает именно то, что я хочу — я могу нажать кнопку, независимо от того, нажимаю ли я на значок или на кнопку (по крайней мере, перекрывающуюся часть — это все, что мне нужно. Спасибо!

Ответ №2:

Я добился желаемого визуального эффекта, поместив кнопку и значок в стопку (вместо стопки внутри кнопки).

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

Так что этот ответ не совсем правильный….

 Stack(
   clipBehavior: Clip.none,
                children: [
                  OutlinedButton(
                  style: scansButtonStyle,
                  onPressed: () {}, // TODO: add later
                  child: Padding(
                    padding: const EdgeInsets.only(left: 50.0),
                    child: Text('CONNECT'),
                  ),
                    ),
                  Positioned(
                    bottom: 6,
                    left: 0,
                    child: CircleAvatar(
                      radius: 30,
                      backgroundColor: Colors.black,
                      child: CircleAvatar(
                        radius: 27,
                        backgroundColor: Colors.white,
                        child: Icon(
                          Icons.bluetooth_connected,
                          color: Colors.black,
                          size: 48,
                        ),
                      ),
                    ),
                  ),
              ]),
 

Комментарии:

1. Я думаю, что один из способов обойти это — сделать значок также кнопкой, которая ссылается на ту же функцию-не уверен, что это самое элегантное решение? Честно говоря, значок в вопросе запускается только частью, перекрывающей кнопку, но она была достаточно близка, чтобы ее было недостаточно заметно, чтобы вызвать проблему, в то время как это решение создает отверстие в кнопке, где оно не может сработать 🙁