Использование GestureDetector для перехвата жестов дочернего элемента MaterialButton

Я хочу иметь MaterialButton для обнаружения onTapDown, onTapUp и onTapCancel.

К сожалению, MaterialButtons обнаруживает только onPressed. Поэтому я обернул его GestureDetector, но для MaterialButtons onPressed имеет @required, поэтому я установил его в () {}. Проблема в том, что даже если я сделаю поведение GestureDetector полупрозрачным, если я нажму на кнопку, будет запущен только обратный вызов onPressed для Button, и я потеряю обратные вызовы onTapDown и onTapUp для GestureDetector. Я получаю onTapDown для срабатывания, только если я долго нажимаю кнопку, и когда я ее отпускаю, запускается onTapCancel. Я никогда не смогу запустить onTapUp таким образом.

Мне по-прежнему нужен MaterialButton из-за его возможностей тактильной / звуковой / визуальной обратной связи.

Я попытался вообще не устанавливать onPressed на MaterialButton, и (как ни странно) он все еще работал, но кнопка была отключена и вообще не давала никакой обратной связи.

GestureDetector(
          behavior: HitTestBehavior.translucent,
          onTapDown: (_) {
            th.handleTap(i, 0);
          },
          onTapUp: (_) {
            th.handleTap(i, 1);
          },
          onTapCancel: () {
            th.handleTap(i, 2);
          },
          child: MaterialButton(
            onPressed: () {},
            child: Container(
              margin: EdgeInsets.all(5),
              child: Icon(icon),
            ),
          )
        )

Изменить: Спасибо, Хьюго Пассос, по какой-то причине я предположил, что MaterialButtons никогда не будет передавать жест своим детям. Я приближаюсь, но меня все еще нет: единственный способ, который я нашел, чтобы соответствовать размеру жеста, - это «зажать» его между двумя контейнерами, что не кажется мне очень элегантным решением. Кстати, даже в этом случае я сталкиваюсь с двумя проблемами:

1: Если я (довольно легко) нажимаю на границу кнопки, у меня все еще срабатывает onPressed MaterialButton вместо обратных вызовов GestureDetector. Я думал, что у него нулевой размер, поэтому он не мог никогда не постучать. Эта проблема не проявляется, если я установил поведение GestureDetector на непрозрачное (все еще странно для меня).

2: Самое важное: я все еще не могу получить встроенные возможности обратной связи MaterialButton, если случайно не запустил его onPressed.

Container(
margin: EdgeInsets.all(2),
        width: buttonSize,
        height: buttonSize,
        child: RaisedButton(
          padding: EdgeInsets.zero,
          onPressed: () {print("onTap");},
          child: Container(
            margin: EdgeInsets.zero,
            width: buttonSize,
            height: buttonSize,
            child: GestureDetector(
              onTapDown: (_) {
                th.handleTap(i, 0);
              },
              onTapUp: (_) {
                th.handleTap(i, 1);
              },
              onTapCancel: () {
                th.handleTap(i, 2);
              },
              child: Icon(icon)
            ),
          ),
        ),
      );

person Matteo Bertino    schedule 15.05.2019    source источник


Ответы (1)


Вы должны сделать наоборот. Вместо того, чтобы оборачивать RaisedButton в GestureDetector, оберните GestureDetector в RaisedButton. Вам также необходимо удалить RaisedButton отступ, чтобы вы могли расширить GestureDetector рабочую область.

RaisedButton(
  padding: EdgeInsets.zero,
  onPressed: () {},
  child: Container(
    height: 40,
    width: 80,
    child: GestureDetector(
      onTapDown: (_) => print('onTapDown'),
      onTapUp: (_) => print('onTapUp'),
      onTapCancel: () => print('onTapCancel'),
      child: Icon(icon),
    ),
  ),
),

Редактировать

Center(
  child: RaisedButton(
    padding: EdgeInsets.zero,
    onPressed: () => print('onPressed'),
    child: GestureDetector(
      onTapDown: (_) => print('onTapDown'),
      onTapUp: (_) => print('onTapUp'),
      onTapCancel: () => print('onTapCancel'),
      child: Container(
        color: Colors.blue,
        height: 40,
        width: 80,
        child: Icon(icon),
      ),
    ),
  ),
);

Однако вы получите небольшую рамку, которая называет onPressed. Если вас это беспокоит, оберните этот код в другой Container, как вы это делали в своем коде.

Вы можете легко получить встроенные RaisedButton возможности обратной связи, вызвав метод onPressButton по адресу onTapUp. Он будет вести себя так же.

RaisedButton(
  ...
  onPressed: onPressButton,
  child: GestureDetector(
    ...
    onTapUp: (_) {
      onPressButton();
      print('onTapUp')
    },
    ...
  ),
),
person Hugo Passos    schedule 15.05.2019
comment
Спасибо, Хьюго, у меня все равно есть проблемы. Я отредактировал свой вопрос. - person Matteo Bertino; 16.05.2019
comment
Предполагая, что я определил onPressButton в другом месте следующим образом: onPressButton() {print("onPressButton");}; Это все еще не работает: вызывается onPressButton, но я не получаю отзывов о кнопках. - person Matteo Bertino; 16.05.2019
comment
Я не понимаю, что вы подразумеваете под обратной связью с кнопкой. Единственная обратная связь, которую может дать кнопка, - это onPressed, верно? Если вызывается onPressButton, как вы не получили отклик на кнопку? - person Hugo Passos; 16.05.2019
comment
Извините за задержку. Я имел в виду обратную связь пользовательского интерфейса, такую ​​как звук, вибрация и эффект всплеска на кнопке. С последним решением все работает так, как должно с точки зрения обратного вызова, но мои кнопки не дают никакой визуальной обратной связи, это просто серые рабочие квадраты. - person Matteo Bertino; 28.05.2019