i am facing an issue when i use a stack and add a child that has a gesture detector and position it outside the parent widget using positioned it doesn't detect gestures anymore , if there is a fix please explain it thank you . my code for the problem :
...List<Widget>.generate(
images.length,
(index) {
return Stack(
clipBehavior: Clip.none,
children: [
Container(
height: deviceWidth / 3.5,
width: deviceWidth / 3.5,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10)),
child: GestureDetector(
onLongPressStart: (details) {},
onTap: () async {
var imageFile = await pickImage();
if (imageFile != null) {
images[index] = makeImage(
isPlaceholder: false,
imageData: await imageFile.readAsBytes());
setState(
() {},
);
}
},
child: images[index],
),
),
Positioned(
left: -10,
top: -15,
child: Container(
alignment: Alignment.center,
height: 30,
width: 30,
decoration: const ShapeDecoration(
shape: CircleBorder(), color: Colors.red),
child: InkWell(
splashColor: Colors.white,
onTap: () {
images.remove(images[index]);
setState(() {});
},
child: const IgnorePointer(
child: Icon(Icons.delete_forever)),
),
),
)
],
);
},
),
i am facing an issue when i use a stack and add a child that has a gesture detector and position it outside the parent widget using positioned it doesn't detect gestures anymore , if there is a fix please explain it thank you . my code for the problem :
...List<Widget>.generate(
images.length,
(index) {
return Stack(
clipBehavior: Clip.none,
children: [
Container(
height: deviceWidth / 3.5,
width: deviceWidth / 3.5,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10)),
child: GestureDetector(
onLongPressStart: (details) {},
onTap: () async {
var imageFile = await pickImage();
if (imageFile != null) {
images[index] = makeImage(
isPlaceholder: false,
imageData: await imageFile.readAsBytes());
setState(
() {},
);
}
},
child: images[index],
),
),
Positioned(
left: -10,
top: -15,
child: Container(
alignment: Alignment.center,
height: 30,
width: 30,
decoration: const ShapeDecoration(
shape: CircleBorder(), color: Colors.red),
child: InkWell(
splashColor: Colors.white,
onTap: () {
images.remove(images[index]);
setState(() {});
},
child: const IgnorePointer(
child: Icon(Icons.delete_forever)),
),
),
)
],
);
},
),
Share
Improve this question
edited Nov 21, 2024 at 6:16
DarkBee
15.6k8 gold badges72 silver badges117 bronze badges
asked Nov 20, 2024 at 23:02
Lemon GrabLemon Grab
511 silver badge7 bronze badges
1 Answer
Reset to default 2This behaviour is intentional. The framework hitTest
goes from parent to children, and by default widget don't allow child to receive hitTest
when it is outside of the parent's box.
To achieve "outside of box" gesture detection of an overflowed child. You could push the child that would overflow to the Overlay
with OverlayPortal
and position it with LayerLink
.
import 'package:flutter/material.dart';
main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('LayerLink'),
),
body: const Center(child: Home()),
),
);
}
}
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.all(20.0),
child: Wrap(
spacing: 10.0,
runSpacing: 10.0,
children: [
MyImage(color: Colors.blue),
MyImage(color: Colors.green),
MyImage(color: Colors.yellow),
MyImage(color: Colors.orange),
MyImage(color: Colors.purple),
MyImage(color: Colors.red),
MyImage(color: Colors.pink),
MyImage(color: Colors.teal),
MyImage(color: Colors.brown),
MyImage(color: Colors.grey),
],
),
);
}
}
class MyImage extends StatefulWidget {
const MyImage({super.key, required this.color});
final Color color;
@override
State<MyImage> createState() => _MyImageState();
}
class _MyImageState extends State<MyImage> {
int count = 0;
final controller = OverlayPortalController();
final link = LayerLink();
@override
void initState() {
super.initState();
controller.show();
}
@override
Widget build(BuildContext context) {
return OverlayPortal(
controller: controller,
child: CompositedTransformTarget(
link: link,
child: Container(
color: widget.color,
height: 100,
width: 100,
alignment: Alignment.center,
child: Text(
"$count",
style: const TextStyle(fontSize: 30),
),
),
),
overlayChildBuilder: (context) {
return Center(
child: CompositedTransformFollower(
link: link,
followerAnchor: Alignment.center,
showWhenUnlinked: false,
child: Container(
alignment: Alignment.center,
height: 30,
width: 30,
decoration: const ShapeDecoration(shape: CircleBorder(), color: Colors.red),
child: InkWell(
splashColor: Colors.white,
onTap: () {
setState(() {
count++;
});
},
child: const IgnorePointer(child: Icon(Icons.delete_forever)),
),
),
),
);
},
);
}
}