It’s about a Flutter web app
I have an FirebaseAnimatedList with ListTiles.
When hovering over a ListTile an Overlay (a Row with 4 clickable IconButtons) attached to this ListTile shall be shown in the upper right corner of the ListTile. When exiting the ListTile the Overlay shall disappear. But the Overlay shall of course not disappear when exiting the ListTile via the Overlay (like in Microsoft Teams).
So I wrapped the ListTile in a MouseRegion. Entering MouseRegion should show the Overlay, exiting should hide the Overlay. And it’s doing so! but of course not what I wanted, since hovering over the Overlay means exiting the ListTile, hiding the Overlay, entering the ListTile, showing the Overlay, hovering over the Overlay, … it’s flickering. So I simply added some Duration, and it’s nearly working fine, but of course not (Thread?-)safe. Sometimes the Overlay doesn’t disappear anymore. I don’t believe that this is a correct approach to this problem.
class ListTileWidget extends StatefulWidget {
final Map dataMap;
const ListTileWidget({Key? key, required this.dataMap}) : super(key: key);
@override
State<ListTileWidget> createState() => _ListTileWidgetState();
}
class _ListTileWidgetState extends State<ListTileWidget> {
final layerLink = LayerLink();
OverlayEntry? entry;
void showOverlay() {
final overlay = Overlay.of(context);
entry = OverlayEntry(
builder: (context) => Positioned(
width: 200,
child: CompositedTransformFollower(
link: layerLink,
showWhenUnlinked: false,
offset: const Offset(0, -20),
followerAnchor: Alignment.topRight,
targetAnchor: Alignment.topRight,
child: buildOverlay(),
),
),
);
overlay.insert(entry!);
}
void hideOverlay() {
entry?.remove();
entry = null;
}
Widget buildOverlay() {
return Material(
color: Colors.grey,
child: Row(
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: () {
print('Button pressed');
},
),
IconButton(
icon: const Icon(Icons.brush),
onPressed: () {
print('Button pressed');
},
),
IconButton(
icon: const Icon(Icons.start),
onPressed: () {
print('Button pressed');
},
),
IconButton(
icon: const Icon(Icons.emoji_emotions),
onPressed: () {
print('Button pressed');
},
),
],
),
);
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: layerLink,
child: MouseRegion(
onEnter: (e) async {
await Future.delayed(const Duration(milliseconds: 200));
showOverlay();
},
onExit: (e) async {
await Future.delayed(const Duration(milliseconds: 500));
hideOverlay();
},
child: ListTile(
leading: const Icon(Icons.person),
title: Text(
widget.dataMap['userName'] + 'n' + widget.dataMap['time'],
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
subtitle: Text(widget.dataMap['message']),
onTap: () {
print('onTap');
},
),
),
);
}
}
ListTile with Overlay (not disappearing anymore)
I’m doing flutter for 6 months now and this is my first question an stackoverflow. I’m running out of ideas with this overlay-problem. Thanks for help!
2
Answers
Looks like I found a solution using a Timer :-)
I also wrapped the Overlay in a MouseRegion. Exiting ListTile sets
that's the main idea. In fact, I use two Timers to make it nicer.
Perhaps there is an easier solution without timers ...
The problem is that you are using Future.delayed() to show and hide the overlay.