Это известная проблема с кнопками и стеками, и я бы посоветовал любому, у кого есть такая проблема, посмотреть это обсуждение на Github .
TL; DR:
При переводе виджета область, которую вы можете нажать, состоит из двух частей:
- области родительского виджета
- области дочернего элемента (здесь плоская кнопка)
См. Рисунок ниже:
Дочерний против родительского против интерактивной области
Обычное решение:
Расширение размера родительского элемента.
Что дает нам что-то вроде этого:
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"),
),
),
),
),
Вот вам можно коснуться в любом месте родительского контейнера.
Решение для вас
На самом деле вы хотели чего-то немного другого: что-нибудь, НО кнопку можно щелкнуть. Для этого вам потребуется:
- GestureDetector, являющийся родителем интерактивной области
- 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 поверх этого Контейнера позволяет нам захватывать любое нажатие внутри этого Контейнера.
Итак, наконец, вот что происходит, когда вы нажимаете, если вы нажимаете:
- За пределами голубого контейнера ничего не происходит.
- Внутри голубого контейнера
- За пределами кнопки GestureController ловит нажатие и заставляет кнопку двигаться
- Внутри кнопки Button ловит касание, ничего не делает с ним (пустой метод) и отмечает это касание как обработанное , из-за чего оно не всплывает в дереве * 1 062 * и, следовательно, GestureController ничего не получает и ничего не происходит.
Надеюсь, это поможет вам и другим понять сложный способ, которым все это работает. Но если принять его, это выглядит красиво;)