Flutter onPressed не работает после перевода FlatButton - PullRequest
0 голосов
/ 21 июня 2020

У меня возникли проблемы с обработкой событий при использовании ScrollView и Transform. Структура макета такая: ScrollView и Transform существуют внутри Stack.

Я хочу, чтобы ScrollView прокручивался при прокрутке за пределами FlatButton в Container(Colors.cyan), событие может проникать в ScrollView.

Нажмите FlatButton на нажмите для работы. Фактически, после двойного щелчка FlatButton он больше не будет перемещаться независимо от того, щелкаете ли вы в исходной или текущей позиции. Элемент управления FlatButton отходит от начальной позиции в пределах диапазона размеров, событие click больше не обнаруживается, но я не понял. код такой:

class EventListener extends StatefulWidget {
  @override
  _EventListenerState createState() => _EventListenerState();
}

class _EventListenerState extends State<EventListener> {

  Offset offset = Offset(0, 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("EventListener"),
      ),
      body: Stack(
        children: <Widget>[
          SingleChildScrollView(
            child: Column(
              children: <Widget>[
                Container(
                  color: Colors.red,
                  height: 200,
                ),
                Container(
                  color: Colors.teal,
                  height: 300,
                ),
                Container(
                  color: Colors.orange,
                  height: 400,
                )
              ],
            ),
          ),
          Container(
            color: Colors.cyan,
            width: double.infinity,
            height: 400,
            alignment: Alignment.center,
            child: SizedBox(
              width: 100,
              height: 100,
              child: Transform.translate(
                offset: offset,
                child: FlatButton(
                  color: Colors.orange,
                  onPressed: () {
                    setState(() {
                      offset += Offset(50, 50);
                    });
                    print('click !');
                  },
                  child: Text("translate"),
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

1 Ответ

1 голос
/ 21 июня 2020

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

TL; DR:

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

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

См. Рисунок ниже:

Дочерний против родительского против интерактивной области

Обычное решение:

Расширение размера родительского элемента.

Что дает нам что-то вроде этого:

Container( 
  width: double.infinity,
  height: 400,
  child: Transform.translate(
    offset: offset,
    child: SizedBox(
      width: 100,
      height: 100,
      child: FlatButton(
        onPressed: () => print('tap button'),
        child: Text("translate"),
      ),
    ),
  ),
),

Вот вам можно коснуться в любом месте родительского контейнера.

Решение для вас

На самом деле вы хотели чего-то немного другого: что-нибудь, НО кнопку можно щелкнуть. Для этого вам потребуется:

  1. GestureDetector, являющийся родителем интерактивной области
  2. FlatButton с методом onPressed, который ничего не делает

Итак, вот последний код, если мы хотим, чтобы синий контейнер был доступен для клика:

import 'package:flutter/material.dart';

main() => runApp(MaterialApp(
  home: EventListener(),
));

class EventListener extends StatefulWidget {
  @override
  _EventListenerState createState() => _EventListenerState();
}

class _EventListenerState extends State<EventListener> {
  Offset offset = Offset(0, 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("EventListener"),
      ),
      body: Stack(
        children: <Widget>[
          SingleChildScrollView(
            child: Column(
              children: <Widget>[
                Container(
                  color: Colors.red,
                  height: 200,
                ),
                Container(
                  color: Colors.teal,
                  height: 300,
                ),
                Container(
                  color: Colors.orange,
                  height: 400,
                )
              ],
            ),
          ),
          GestureDetector(
            onTap: () {
              setState(() {
                offset += Offset(50, 50);
              });
            },
            child: Container(
              width: double.infinity,
              height: 400,
              color: Colors.cyan,
              alignment: Alignment.center,
              child: Transform.translate(
                offset: offset,
                child: SizedBox(
                  width: 100,
                  height: 100,
                  child: FlatButton(
                    color: Colors.orange,
                    onPressed: () {},
                    child: Text("translate"),
                  ),
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

Почему это работает

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

Кроме того, добавление GestureDetector поверх этого Контейнера позволяет нам захватывать любое нажатие внутри этого Контейнера.

Итак, наконец, вот что происходит, когда вы нажимаете, если вы нажимаете:

  1. За пределами голубого контейнера ничего не происходит.
  2. Внутри голубого контейнера
    1. За пределами кнопки GestureController ловит нажатие и заставляет кнопку двигаться
    2. Внутри кнопки Button ловит касание, ничего не делает с ним (пустой метод) и отмечает это касание как обработанное , из-за чего оно не всплывает в дереве * 1 062 * и, следовательно, GestureController ничего не получает и ничего не происходит.

Надеюсь, это поможет вам и другим понять сложный способ, которым все это работает. Но если принять его, это выглядит красиво;)

...