Update:
#override
Widget build(BuildContext context) {
return new Container(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Container(
height: 220.0,
width: MediaQuery.of(context).size.width,
child: new GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Column(
children: <Widget>[
SizedBox(height: 40.0),
Row(
children: <Widget>[
Expanded(
child: Stack(
children: [
Center(
child: Text(
'Profile',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Lato',
color: Colors.white,
fontSize: 50.0,
fontWeight: FontWeight.w700,
),
),
),
Positioned(
right: 8,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 400)),
PopupMenuButton<String>(
icon: Icon(
Icons.settings,
color: Colors.white,
size: 30.0,
),
onSelected: choiceAction,
itemBuilder: (BuildContext context) {
return Constants.choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
),
),
],
),
),
],
),
I am trying to implement a DropDownButton inside the OnPressed command of an IconButton, so that when the icon is pressed, a drop down menu is shown.
Update: I've updated my code with the suggestion made, however the icon does not appear.
I'm not sure if this is a problem with my widget tree.
Updated Answer
Please check this code:
class DropdownMenu extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 400)),
PopupMenuButton<String>(
icon: Icon(Icons.settings),
onSelected: choiceAction,
itemBuilder: (BuildContext context) {
return Constants.choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
));
}
}
class Constants {
static const String FirstItem = 'First Item';
static const String SecondItem = 'Second Item';
static const String ThirdItem = 'Third Item';
static const List<String> choices = <String>[
FirstItem,
SecondItem,
ThirdItem,
];
}
void choiceAction(String choice) {
if (choice == Constants.FirstItem) {
print('I First Item');
} else if (choice == Constants.SecondItem) {
print('I Second Item');
} else if (choice == Constants.ThirdItem) {
print('I Third Item');
}
}
Note: This is not dropdown menu but i think this is what you want.
Old answer
You can try using showDialog
child: Row(
children: <Widget>[
IconButton(
icon: Icon(
Icons.settings,
color: Colors.black,
size: 30.0,
),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Country List'),
content: new ListView(
children: <Widget>[
new Column(
children: <Widget>[
new DropdownButton<String>(
items: <String>['A', 'B', 'C', 'D', 'E', 'F', 'G'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
),
],
),
],
),
);
});
})
],
)
Related
Is there a way to close the selection menu of a DropdownButton containing all the DropdownMenuItems when an onTap function is executed (GestureDetector inside a DropdownMenuItem)?
Here is my implementation of the approach of Alperen Baskaya (in a slightly reduced version so that it is understandable). This approach however does not work yet and I am not sure whether it is because I have implemented it incorrectly or because the approach does not work for my problem.
class _BoatSelectionState extends State<BoatSelection> {
FocusNode focusNode;
#override
void initState() {
super.initState();
focusNode = FocusNode();
}
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child:
DropdownButtonHideUnderline(
child: DropdownButton<Boat>(
focusNode: focusNode,
icon: Icon(
Icons.keyboard_arrow_down_rounded,
color: Colors.black,
),
isExpanded: true,
value: selectedBoat,
onChanged: (Boat _boat) => Provider.of<BoatStreamsCubit>(context, listen: false).setBoat(_boat),
selectedItemBuilder: (BuildContext context) {
return widget.boats.map<Widget>((Boat boat) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BoatClassLogo(boat: boat),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: DesignValues.paddingMd),
child: BoatInformation(boat: boat),
),
),
],
);
}).toList();
},
items: widget.boats.map<DropdownMenuItem<Boat>>((Boat _boat) {
return DropdownMenuItem<Boat>(
value: _boat,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: DesignValues.paddingMd),
child: BoatClassLogo(boat: _boat),
),
Expanded(
child: BoatInformation(boat: _boat),
),
GestureDetector(
onTap: () {
focusNode.unfocus();
Navigator.push(context, MaterialPageRoute(builder: (context) => BoatForm(CreationState.edit, _boat)));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Icon(
Icons.edit,
color: AppColors.primary,
),
),
),
],
),
);
}).toList(),
),
),
),
],
);
}
}
I looked up the internal implementation of DropdownMenu in dart.
The popover for DropdownMenu is created by using Navigator.push(). It waits for the user to click an item and returns the value with Navigator.pop(). So we can pop the popover manually by getting the dropdown's context via a GlobalKey.
late GlobalKey dropdownKey;
#override
void initState() {
super.initState();
dropdownKey = GlobalKey();
}
...
DropdownButton<Boat>(
key: dropdownKey,
...)
And remove it using Navigator.pop()
GestureDetector(
onTap: () {
Navigator.pop(dropdownKey.currentContext);
Full code:
class _BoatSelectionState extends State<BoatSelection> {
GlobalKey dropdownKey;
#override
void initState() {
super.initState();
dropdownKey = GlobalKey(); // Init GlobalKey, allows to close the DropdownButton
}
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child:
DropdownButtonHideUnderline(
child: DropdownButton<Boat>(
key: dropdownKey,
icon: Icon(
Icons.keyboard_arrow_down_rounded,
color: Colors.black,
),
isExpanded: true,
value: selectedBoat,
onChanged: (Boat _boat) => Provider.of<BoatStreamsCubit>(context, listen: false).setBoat(_boat),
selectedItemBuilder: (BuildContext context) {
return widget.boats.map<Widget>((Boat boat) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BoatClassLogo(boat: boat),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: DesignValues.paddingMd),
child: BoatInformation(boat: boat),
),
),
],
);
}).toList();
},
items: widget.boats.map<DropdownMenuItem<Boat>>((Boat _boat) {
return DropdownMenuItem<Boat>(
value: _boat,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: DesignValues.paddingMd),
child: BoatClassLogo(boat: _boat),
),
Expanded(
child: BoatInformation(boat: _boat),
),
GestureDetector(
onTap: () {
Navigator.pop(dropdownKey.currentContext); // Closes the dropdown
Navigator.push(context, MaterialPageRoute(builder: (context) => BoatForm(CreationState.edit, _boat)));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Icon(
Icons.edit,
color: AppColors.primary,
),
),
),
],
),
);
}).toList(),
),
),
),
],
);
}
}
If I got you right you can use focus node for dropdown menu.
FocusNode dropdown;
Initializing in initstate is needed;
dropdown = FocusNode();
child: DropdownButtonHideUnderline(
child: DropdownButton <String>(
focusNode: dropdown,
Then when you may think to close this menu execute in ontap;
dropdown.unfocus();
I want to display a Row for each DropdownMenuItem of DropdownButton in Flutter. I want to display an icon and a text in the Row.
If anybody can please help me with it.
This is how I've tried. I've tried to add the Icon and Text in a Row for each item in the DropdownButton.
class _LoginPageState extends State<LoginPage> {
Widget dropdownValue = Row(
children: [Icon(Icons.star), Text("One")],
);
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Container(
child: ListView(
padding: EdgeInsets.all(20.0),
children: [
Padding(padding: EdgeInsets.all(displayHeight(context) * 0.02)),
Center(
child: Image(
image: AssetImage('assets/images/sendmelogo.png'),
height: displayHeight(context) * 0.07,
),
),
Padding(padding: EdgeInsets.all(displayHeight(context) * 0.02)),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.grey[200],
),
// padding: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Sending to:", textAlign: TextAlign.start),
DropdownButton<Widget>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (Widget newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <Widget>[
Row(
children: [Icon(Icons.star), Text("One")],
),
Row(
children: [Icon(Icons.plus_one), Text("Two")],
)
].map<DropdownMenuItem<Widget>>((Widget value) {
return DropdownMenuItem<Widget>(
value: value,
child: Container(
child: value,
),
);
}).toList(),
),
],
),
),
DropdownButton<String>(
items: <String>['Hillary', 'Joe', 'Felix', 'Monica'].map((name) {
return DropdownMenuItem<String>(
value: name,
// Your row here:
child: Row(
children: [
Icon(Icons.person),
Text(name),
],
),
);
}).toList(),
onChanged: (selectedName) {
// do some action here
},
),
i would like to show a list of radiobuttons? this radiobuttons are contained in ListTile widget, i tried some code but nothing appears :
when i put a single radiobutton , this appears but when i put a listview nothing appears on the page including others widgets
Widget build(BuildContext context) {
return StoreConnector<MMpataState, MMpataViewModel>(
converter: MMpataViewModel.convertStateToViewModel,
builder: (BuildContext context, MMpataViewModel vm) {
// print(vm.state.subscriptions2);
if (vm.state.isSubscriptions2loaded &&
vm.state.subscriptions2.length < 1) {
return Scaffold(
appBar: AppBar(
title: Text("Aucune donnée"),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Center(
child: Text(
"Nous n'avons trouvé aucune souscription pour le produit
sélectionné.",
),
),
),
);
}
return Scaffold(
appBar: AppBar(
title: Text(!vm.state.isSubscriptions2loaded ? "Chargement ... " :
vm.state.subscriptions2[0].product.libelle),
),
body: MMpataLoader(
inAsyncCall: _isLoading || !vm.state.isSubscriptions2loaded,
child:
Column(
children: <Widget>[
Form(
child: new Container(
color: Color(0xffFFFFFF),
child:
Column( crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget> [
Padding(padding:EdgeInsets.fromLTRB(25.0, 0.0,
0.0, 0.0),
child: Column(crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget> [
Text(""),
Text(vm.state.subscriptions2[0].product.libelle,
textAlign:TextAlign.left,style:TextStyle()),
Text(vm.state.subscriptions2[0].product.description,
textAlign: TextAlign.left),
Expanded(
child: ListView.builder(shrinkWrap:true,
itemCount: vm.state.subscriptions2.length,
itemBuilder: (context, index) {
return RadioListTile<double>(
title:Text(
"${vm.state.subscriptions2[index].quota.libelle}
(${vm.state.subscriptions2[index].amount} CDF)"),
value: vm.state.subscriptions2[index].amount,
groupValue:vm.state.subscriptions2[index].amount,
onChanged: (double value) {
setState(() {
vm.state.subscriptions2[index].amount = value;
});
},
);
}),
),
])
),
_getActionButtons(vm),
SizedBox(height: 100)
]) ],
),
),
)
],
),
),
);
},
);
}
i have this error while running : RenderBox was not laid out
Hi The problem is I have multiple groups of RadioButtons hence can't figure out how onChanged method will work for each group.
I have a list of students and want to make a widget where a teacher can mark attendance of students by clicking on one of the Radio Buttons( present,absent,holiday,half day etc.)
Here is the implementation
#override
Widget build(BuildContext context) {
print('number students ${studentList.students.length.toString}');
return ListView.builder(
itemCount: studentList.students.length,
itemBuilder: (context, index) {
var gp = studentList.students[index].id;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
child: ListTile(
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
studentList.students[index].name,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
),
leading: CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
studentList.students[index].details['photo'])),
trailing: Column(
children: <Widget>[],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Phone: ' +
studentList.students[index].details['phone']),
Text('Batches:'),
Container(
width: MediaQuery.of(context).size.width,
height: 50,
child: ListView.builder(
itemCount: studentList.students[index].batches.length,
itemBuilder: (context, batchIndex) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(studentList
.students[index].batches[batchIndex].name),
],
);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Column(
children: <Widget>[
Radio(
groupValue: gp,
value: 0,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
),
Text('P')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 1,
),
Text('Ab')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 2,
),
Text('Hd')
],
),
Column(
children: <Widget>[
Radio(
groupValue: gp,
onChanged: (int e) {
print(e);
print(gp);
updateSelectedAttendance(gp, e);
},
value: 3,
),
Text('H')
],
)
],
),
)
],
),
),
),
);
});
}
updateSelectedAttendance(int gp, int e) {
setState(() {
gp = e;
print('gp ${gp.toString()} -- e ${e.toString()}');
});
}
Here because there would be multiple students , hence there would be multiple groups of Radio Buttons so I have assigned each group a groupValue of id of the individual student. And because there are 4 radio buttons for each student (present,absent,holiday,halfday), I have assigned values of 0,1,2,3. And in onChanged method I am equating gp=value;
But it is not behaving the way I want it to behave.
//For the deom purpose I'm using Map List...
//Replace the above with your custom model
List<Map> studentList=[];
//Create attendance list to hold attendance
Map<String,String> attendance={};
List<String> labels=['P','Ab','Hd','H'];
#override
void initState() {
super.initState();
getData();
}
getData(){
//Use your own implementation to get students data
//For deom I'm using offline data
studentList.add({
'id':'ID1',
'name':'Naveen Avidi',
'details':'A Programmer'
//other fields...
});
attendance['ID1']='P';
//or null if emtpy
studentList.add({
'id':'ID2',
'name':'Ram',
'details':'An Engineer'
//other fields...
});
attendance['ID2']='Ab';
//or null if emtpy
studentList.add({
'id':'ID3',
'name':'Satish',
'details':'A Developer'
//other fields...
});
attendance['ID3']='Hd';
//or null if emtpy
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text('Title')),
body: Container(
color:Colors.white,
child: ListView.builder(
itemCount: studentList.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color:Colors.cyan,
elevation: 10,
child: ListTile(
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
studentList[index]['name'],
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold,color:Colors.black),
),
),
leading: CircleAvatar(
radius: 30,
//no pic available
),
trailing: Column(
children: <Widget>[],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Phone: ' +
studentList[index]['details'],
style:TextStyle(color:Colors.black)),
Text('Batches:',style:TextStyle(color:Colors.black)),
// Container(
// width: MediaQuery.of(context).size.width,
// height: 50,
// child: ListView.builder(
// itemCount: studentList.students[index].batches.length,
// itemBuilder: (context, batchIndex) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: <Widget>[
// Text(studentList
// .students[index].batches[batchIndex].name),
// ],
// );
// },
// ),
// ),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: labels.map((s){
return Column(
children: <Widget>[
Radio(
groupValue: attendance[studentList[index]['id']],
value: s,
onChanged: (newValue) {
setState((){
attendance[studentList[index]['id']]=newValue;
});
},
),
Text(s,style:TextStyle(color:Colors.black))
],
);
}).toList(),
),
)
],
),
),
),
);
})
),
);
}
i am trying to retrieve data from firestore as dropdown list, got this tutorial and error show up, please help, totally new with flutter.
This function has a return type of 'Row', but doesn't end with a return statement.
Try adding a return statement, or changing the return type to 'void'.
here is the code :
class _MyHomePageState extends State<MyHomePage> {
var selectedCurrency, selectedType;
final GlobalKey<FormState> _formKeyValue = new GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(
Icons.edit,
color: Colors.white,
),
onPressed: () {}),
title: Container(
alignment: Alignment.center,
child: Text("Account Details",
style: TextStyle(
color: Colors.white,
)),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.edit,
size: 20.0,
color: Colors.white,
),
onPressed: null,
),
],
),
body: Form(
key: _formKeyValue,
autovalidate: true,
child: new ListView(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
children: <Widget>[
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.edit,
size: 25.0,
color: Color(0xff11b719),
),
SizedBox(width: 50.0),
],
),
SizedBox(height: 40.0),
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("currency").snapshots(),
builder: (context, snapshot) {
}),
SizedBox(
height: 150.0,
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
RaisedButton(
color: Color(0xff11b719),
textColor: Colors.white,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text("Submit", style: TextStyle(fontSize: 24.0)),
],
)),
onPressed: () {},
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0))),
],
),
],
),
));
}
}
I'm totally new to Flutter myself, but it appears the method build of the MyHomePageState class does have a return statement. In fact, all the method body is wrapped inside that return statement:
Widget build(BuildContext context) {
return Scaffold(
...
)}
That build method returns a complete description of your page, including the Row you mentioned in your question deeply nested in structure:
return Scaffold(
...
body: Form(
...
child: new ListView(
...
children: <Widget>[
SizedBox(height: 20.0),
Row( <---------------- here it is
...
Or did I missed your point?