'How to get a floating box when i click on a button in flutter
Solution 1:[1]
You could use the native Flutter Widget https://api.flutter.dev/flutter/material/ExpansionPanel-class.html or try a package like https://pub.dev/packages/expandable
Solution 2:[2]
You could use an ExpansionTile. It does exactly what you are looking for.
Code sample:
Center(
child: ExpansionTile(
iconColor: Colors.red,
title: const Text('More details'),
children: [
ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('Name'),
Text('Ankit'),
],
)),
ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('Grade'),
Text('9th'),
],
)),
ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('Date of birth'),
Text('21-04-2008'),
],
)),
],
),
)
Keep in mind that in the children
you could put any widget, even a container, as:
EDIT
After reading your clarifying comment this is what I made:
Obviously it's a basic floating box, but you can customize it.
I used a Stack to overlap widgets and a boolean to check if you need to show or not the infobox.
bool visibile = false;
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () => setState(() {
visibile = !visibile;
}),
icon: const Icon(Icons.remove_red_eye)),
Stack(
alignment: Alignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: const [
ElevatedButton(
onPressed: null,
child: Text("Check In"),
),
TextField()
],
),
),
visibile
? Container(
width: MediaQuery.of(context).size.width * .8,
height: MediaQuery.of(context).size.height * .5,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
offset: Offset.fromDirection(1, 2),
spreadRadius: 1,
blurRadius: 3,
color: Colors.grey)
],
borderRadius: const BorderRadius.all(Radius.circular(20)),
border: Border.all(
color: Colors.orange,
width: 2,
style: BorderStyle.solid)),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Academic year',
style: TextStyle(color: Colors.grey),
),
Text('2023'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Student name',
style: TextStyle(color: Colors.grey),
),
Text('Ankit'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Grade',
style: TextStyle(color: Colors.grey),
),
Text('9th'),
],
),
],
),
),
),
)
: Container(),
],
),
],
))
Having the button outside the Stack prevents the InfoBox to hide it and makes it so you can click it at any time.
I have no idea why, but someone with enough privileges keeps deleting my comments on this answer.
Solution 3:[3]
If you Want the widget float on the other widgets, you can use OverlayEntry. There is a medium article/guide about this: Click to read.
Abstract:
first you need a global key, an overlay widget and the other variables below:
GlobalKey overlayKey = LabeledGlobalKey("button_icon");
late OverlayEntry overlayEntry;
late Size buttonSize;
late Offset buttonPosition;
bool isMenuOpen = false;
then add the global key to your button's key proprty:
key: context.read<MainViewModel>().overlayKey,
then, find the clicked button using this function:
findButton() {
RenderBox renderBox =
overlayKey.currentContext!.findRenderObject() as RenderBox;
buttonSize = renderBox.size;
buttonPosition = renderBox.localToGlobal(Offset.zero);
}
then, a builder:
OverlayEntry overlayEntryBuilder() {
return OverlayEntry(
builder: (context) {
return Positioned(
top: buttonPosition.dy + buttonSize.height * 4 / 5,
left: buttonPosition.dx - (buttonSize.width / 2) - 32,
// width: buttonSize.width,
child: YourWidgetThatWillOpenWhenYouClickTheButton(),
);
},
);
}
you can play around with the values in the Positioned widget to get the overlay where you want it.
now you can call these functions to open/close the overlay:
void openMenu(BuildContext context) {
findButton();
overlayEntry = overlayEntryBuilder();
Overlay.of(context)!.insert(overlayEntry);
isMenuOpen = !isMenuOpen;
}
void closeMenu() {
overlayEntry.remove();
isMenuOpen = !isMenuOpen;
}
like this:
IconButton(
key: context.read<MainViewModel>().overlayKey,
onPressed: () {
if (!context.read<MainViewModel>().isMenuOpen) {
context.read<MainViewModel>().openMenu(context);
} else {
context.read<MainViewModel>().closeMenu();
}
},
check the medium article for the detailed explanation.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | João Soares |
Solution 2 | |
Solution 3 | Arash Mohammadi |