Flutter onPressed not works after FlatButton translate
This is a known difficulty with Buttons and Stacks and I would advise anyone with this kind of problem to look at this discussion on Github.
TL;DR:
When translating a widget, the area which you can tap is made of two things:
- The area of the parent widget
- The area of the child (the Flatbutton here)
See the picture below:
The usual solution:
Expanding the size of the parent.
Which gives us something like this:
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"),
),
),
),
),
Here you can tap anywhere in the parent Container.
Solution for you
You actually wanted something a bit different: That anything BUT the button is clickable. For that you need:
- a GestureDetector being the parent of the clickable area
- a FlatButton with a onPressed method which does nothing
So here is the final code if we only want the blue container to be clickable:
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"),
),
),
),
),
)
],
),
);
}
}
Why this works
As explained previously, the parent being the cyan Container, any area in this container will make the button clickable.
Furthermore adding a GestureDetector on top of this Container allow us to capture any tap within this Container.
So finally here is what happens when you click, if you click:
- Outside the cyan Container, nothing happens.
- Inside the cyan Container
- Outside the button, the GestureController catch the tap and makes the button move
- Inside the button, the Button catches the tap, does nothing with it (empty method), and mark this tap as treated which causes it not to bubble up in the tree and therefore the GestureController gets nothing and nothing happens.
Hope this helps you and other understand the tricky way all of this works. Once you embrace it it's kinda beautiful though ;)
Jeong Woo
Updated on December 21, 2022Comments
-
Jeong Woo over 1 year
I have encountered some problems with event handling when using
ScrollView
andTransform
. The layout structure is like this,ScrollView
andTransform
exist insideStack
.I want the
ScrollView
to scroll when scrolling outside theFlatButton
inContainer(Colors.cyan)
, event can penetrate to ScrollView.Click
FlatButton
onPress to work. In fact, after clickingFlatButton
twice, it will no longer move whether you click the initial position or the current position. TheFlatButton
control moves away from the initial position within the size range, the click event is no longer detected, but I did not understand. the code is as follows: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"), ), ), ), ) ], ), ); } }
-
HasilT about 4 yearsPlease explain what you are trying to achieve here, or what is your end results should be
-
Jeong Woo about 4 yearsSorry, it may not be described clearly, I updated the question.
-
-
Lulupointu about 4 years@JeongWoo I would recommend you to read my new explanation, it's much better and flexible!