Call a Widget based on the result of an If statement Flutter - flutter

I want to be able to call either one of two different widgets based on the result of an if statement.
I am able to get a Text Widget to show two different answers based on the result of the first dropdown box, but I am not able to call another widget the same way ...
import 'package:flutter/material.dart';
class FilterPage extends StatefulWidget {
const FilterPage({Key? key}) : super(key: key);
#override
State<FilterPage> createState() => _FilterPageState();
}
class _FilterPageState extends State<FilterPage> {
String firstDropdownValue = 'Option A';
String secondDropdownValue = 'Option B';
#override
void dispose() {
super.dispose();
}
static const String _title = 'Filter Code Sample';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Padding(
padding: EdgeInsets.all(4),
),
],
title: Column(
children: [
Text(
'Filter',
style: TextStyle(fontSize: 22, color: Colors.amberAccent),
),
],
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'What are the Options ?',
style: TextStyle(fontSize: 16, color: Colors.white),
),
/*
* This is the first dropdown that is called, This dropdown provides
* two possible options,
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
/*
* So this is the if Statement that works based upon the first
* drop down box's answer...
*
* The problem is I can not get the system to call another Drop down Butten
* Widget based on the answer of the first DropdownBox,
* However, i can get a Text Widget to print...
* */
Text((() {
if (firstDropdownValue == 'Option A') {
return "Option is Option A";
}
return "Option is Option B";
})()),
/*
* This is the second dropbox that I would like to be called if the
* previous statement is met instead of the Text Widget above...
*(DROPBOX 2)
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 1',
'Option 2',
'Option 3',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
/*
* This is also drop box two, but this dropbox with these different
* options should be called when the if statement is not met ..
*(DROPBOX 2)
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 4',
'Option 5',
'Option 6',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
],
),
),
),
);
}
}
The flow diagram is maybe easier to get the whole picture from.

You can use a if(condition)...[widgetA] else...[WidgetB] structure:
class _FilterPageState extends State<FilterPage> {
String firstDropdownValue = 'Option A';
String secondDropdownValue = 'Option B';
#override
void dispose() {
super.dispose();
}
static const String _title = 'Filter Code Sample';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Padding(
padding: EdgeInsets.all(4),
),
],
title: Column(
children: [
Text(
'Filter',
style: TextStyle(fontSize: 22, color: Colors.amberAccent),
),
],
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'What are the Options ?',
style: TextStyle(fontSize: 16, color: Colors.white),
),
/*
* This is the first dropdown that is called, This dropdown provides
* two possible options,
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
if(firstDropDownValue)...[
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 1',
'Option 2',
'Option 3',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
] else ...[
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 4',
'Option 5',
'Option 6',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
]
],
),
),
),
);
}
}

Not the best approach for this probably, but you can use a Builder widget, inside it put your if statement and if you don't want to show your widget there, return SizedBox.shrink() instead (don't forget to setState((){}) so that the widget containing them both rebuilds them. But a better answer may be using Bloc or some other state management package. Or even ValueNotifiers and ValueListenableBuilders to update your UI only where it's needed.

One solution here is to use an inline if condition like this:
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
firstDropdownValue == 'Option A'?
DropdownButton(/*first dropdown*/) :
DropdownButton(/*second dropdown*/),
The other is creating a Widget variable at the beginning of the build method and giving it a value before returning the Scaffold, then put the created variable as one of the Column children:
#override
Widget build(BuildContext context) {
Widget bottomDropdown;
if (firstDropdownValue == 'Option A'){
bottomDropdown = DropdownButton(/*first dropdown*/);
} else {
bottomDropdown = DropdownButton(/*second dropdown*/);
}
return Scaffold(
appBar: AppBar(
//...other code
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
bottomDropdown,

You can use the Dart short if form: if ? then : else.
Since the only thing that changes are the dropdown options, you can dynamically change them without the need to use another widget.
import 'package:flutter/material.dart';
class FilterPage extends StatefulWidget {
const FilterPage({Key? key}) : super(key: key);
#override
State<FilterPage> createState() => _FilterPageState();
}
class _FilterPageState extends State<FilterPage> {
String firstDropdownValue = '';
String secondDropdownValue = 'Option B';
#override
void dispose() {
super.dispose();
}
static const String _title = 'Filter Code Sample';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Padding(
padding: EdgeInsets.all(4),
),
],
title: Column(
children: [
Text(
'Filter',
style: TextStyle(fontSize: 22, color: Colors.amberAccent),
),
],
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'What are the Options ?',
style: TextStyle(fontSize: 16, color: Colors.white),
),
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
if(firstDropdownValue.isNotEmpty)
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
firstDropdownValue == 'Option A' ?
...['Option 1',
'Option 2',
'Option 3'] : ...['Option 5',
'Option 6',
'Option 7']
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
],
),
),
),
);
}
}

Related

Selected value from DropdownButton not showing in Flutter

I have a DropdownButton which displays user type.
List<String> items = ['Engineer', 'Technician', 'Sales'];
String? currentSelectedValue;
child: DropdownButtonHideUnderline(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20.0),
child: DropdownButton<String>(
dropdownColor: Colors.blue.shade100,
isExpanded: true,
hint: Text('Select the user Type'),
onChanged: (newValue) {
setState(() {
currentSelectedValue = newValue;
});
print(currentSelectedValue);
},
items: items.map((String value) {
return DropdownMenuItem(
value: value,
child: Text(
value,
style: TextStyle(color: Colors.black),
),
);
}).toList(),
value: currentSelectedValue,
),
),
),
I can see the list, but when I select a value, it is not displaying on the Text portion of the DropdownButton. I could see the selected value printed in the console.
Can anyone help me to find the mistake?
Make sure to put currentSelectedValue outside the build method.
class Ft extends StatefulWidget {
const Ft({super.key});
#override
State<Ft> createState() => _FtState();
}
class _FtState extends State<Ft> {
List<String> items = ['Engineer', 'Technician', 'Sales'];
String? currentSelectedValue;
#override
Widget build(BuildContext context) {
return Scaffold(
body: DropdownButtonHideUnderline(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: DropdownButton<String>(
dropdownColor: Colors.blue.shade100,
isExpanded: true,
hint: Text('Select the user Type'),
onChanged: (newValue) {
setState(() {
currentSelectedValue = newValue;
});
print(currentSelectedValue);
},
items: items.map((String value) {
return DropdownMenuItem(
value: value,
child: Text(
value,
style: TextStyle(color: Colors.black),
),
);
}).toList(),
value: currentSelectedValue,
),
),
),
);
}
}

how to make unselected color using radiotiles

I know that I can wrap my radio widgets with theme widget but in my case, i use different ways. how to make my radio button have a grey background color when on unselected?
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RadioListTile<SingingCharacter>(
title: const Text('Akaun Individu', style: TextStyle(fontWeight: FontWeight.bold),),
subtitle: Text('Membuat pembayaran untuk diri sendiri'),
controlAffinity: ListTileControlAffinity.trailing,
value: SingingCharacter.akaunSendiri,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
),
Divider(thickness: 2),
RadioListTile<SingingCharacter>(
title: const Text('Akaun Syarikat', style: TextStyle(fontWeight: FontWeight.bold),),
subtitle: Text('Membuat pembayaran untuk organisasi'),
controlAffinity: ListTileControlAffinity.trailing,
value: SingingCharacter.akaunSyarikat,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
),
],
);
}
}
You can do this with overriding theme data.
Example:
...
body: Center(
child: Theme(
data: Theme.of(context).copyWith(
unselectedWidgetColor: Colors.purple,
),
child: Column(
children: [
RadioListTile<String>(
title: const Text(
'RadioListTile 1',
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: const Text('Selected'),
controlAffinity: ListTileControlAffinity.trailing,
value: 'value',
groupValue: 'value',
onChanged: (String? value) {},
),
RadioListTile<String>(
title: const Text(
'RadioListTile 2',
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: const Text('Unselected'),
controlAffinity: ListTileControlAffinity.trailing,
value: 'value',
groupValue: 'valuex',
onChanged: (String? value) {},
),
],
),
),
),
...
add this property to your tile tileColor: varUnselect ? Colors.grey : Colors.transparent, varUnselect is get value of unselect radio

Flutter how to user hint and value DropdownButton

While coding an app i realized, that if you use a hint: with the DropdownButton and a value you only see the value. After some research and trying to work my way around it i finally found a solution. Idk if this is helpful or not but i wanted to share this with you and maybe it does help you in your own project. But without further ado here is the "not functional code":
import 'package:flutter/material.dart';
void main() => runApp(const ButtonClass());
class ButtonClass extends StatefulWidget {
const ButtonClass({Key? key}) : super(key: key);
#override
State<ButtonClass> createState() => _ButtonClassState();
}
class _ButtonClassState extends State<ButtonClass> {
List<DropdownMenuItem<String>> get dropdownItems {
List<DropdownMenuItem<String>> menuItems = [
const DropdownMenuItem(child: Text("One"), value: "Option1"),
const DropdownMenuItem(child: Text("Two"), value: "Option2"),
const DropdownMenuItem(
child: Text("Three"),
value: "Option3",
),
const DropdownMenuItem(
child: Text("Four"),
value: "Option4",
),
const DropdownMenuItem(
child: Text("Five"),
value: "Option5",
),
];
return menuItems;
}
String selectedValue = "Option1";
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(
width: 200.0,
height: 200.0,
child: DropdownButtonHideUnderline(
child: DropdownButton(
isExpanded: true,
hint: const Center(
child: FittedBox(
fit: BoxFit.contain,
child: Text(
"Displayed Text",
style: TextStyle(
color: Colors.black,
fontSize: 30.0,
fontFamily: 'Arial',
),
),
),
),
items: dropdownItems,
value: selectedValue,
onChanged: (String? newValue) {
setState(() {
selectedValue = newValue!;
});
},
),
),
),
),
),
);
}
}
And here is the solution:
Change the
String selectedValue = "Option1";
to (example)
String? _selectedColor;
and also change
value: selectedValue,
onChanged: (String? newValue) {
setState(() {
selectedValue = newValue!;
});
},
to
value: _selectedColor,
onChanged: (String? newValue) {
setState(() {
_selectedColor= newValue!;
});
},
Here is the full main.dart file:
import 'package:flutter/material.dart';
void main() => runApp(const ButtonClass());
class ButtonClass extends StatefulWidget {
const ButtonClass({Key? key}) : super(key: key);
#override
State<ButtonClass> createState() => _ButtonClassState();
}
class _ButtonClassState extends State<ButtonClass> {
List<DropdownMenuItem<String>> get dropdownItems {
List<DropdownMenuItem<String>> menuItems = [
const DropdownMenuItem(child: Text("One"), value: "Option1"),
const DropdownMenuItem(child: Text("Two"), value: "Option2"),
const DropdownMenuItem(
child: Text("Three"),
value: "Option3",
),
const DropdownMenuItem(
child: Text("Four"),
value: "Option4",
),
const DropdownMenuItem(
child: Text("Five"),
value: "Option5",
),
];
return menuItems;
}
String? _selectedColor;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(
width: 200.0,
height: 200.0,
child: DropdownButtonHideUnderline(
child: DropdownButton(
isExpanded: true,
hint: const Center(
child: FittedBox(
fit: BoxFit.contain,
child: Text(
"Displayed Text",
style: TextStyle(
color: Colors.black,
fontSize: 30.0,
fontFamily: 'Arial',
),
),
),
),
items: dropdownItems,
value: _selectedColor,
onChanged: (String? newValue) {
setState(() {
_selectedColor = newValue!;
});
},
),
),
),
),
),
);
}
}

Dropdown is not keeping the value selected

I am working on a dropdown and I have the values in a variable, but I can't get the selected value to be shown, instead is always a static value on.
So far I did this:
class DropDownWidget extends State {
String dropdownValue = 'Activities';
String holder = '';
List<String> postType = ['Activities', 'Sell/buy', 'New Friends', 'City Recommendations', 'Post'];
void getDropDownItem() {
setState(() {
holder = dropdownValue;
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 100,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/blue.png'),
fit: BoxFit.cover,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
child: DropdownButton<String>(
value: dropdownValue,
icon: Icon(
Icons.keyboard_arrow_down_outlined,
color: TheBaseColors.lightRed,
),
iconSize: 30,
elevation: 16,
style: TextStyle(color: TheBaseColors.lightRed, fontSize: 18),
onChanged: (String data) {
setState(() {
dropdownValue = data;
});
switch (data) {
case 'Activities':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CreateActivity()),
);
break;
case 'Sell/buy':
Navigator.push(
context,
}
},
items: postType.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
],
),
);
}
}
I have saved the dropdow value in a variable and then set it in the SetState, but how to show the selected item each time?
Try This
String dropdownValue = 'Activities';
DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['Activities', 'Sell/buy', 'New Friends', 'City Recommendations', 'Post']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),

Bottom overflow while having multiple line item in dropdown flutter

I have multiple line items in the dropdown menu in flutter like this :
It is shown perfectly fine in the dropdown pop up but in dropdown button it shows bottomoverflow like this :
Here is code for the same :
DropdownButtonHideUnderline(
child: DropdownButton(
items: addresses.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: SizedBox(
height: 10 * SizeConfig.heightMultiplier,
child: Column(
children: [
SizedBox(height: 1.5 * SizeConfig.heightMultiplier),
new Text(value, overflow: TextOverflow.clip),
SizedBox(height: 1.5 * SizeConfig.heightMultiplier),
],
),
),
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_selectedShippingAddress = newValue;
});
},
hint: Text("Select address"),
selectedItemBuilder: (BuildContext context) {
return addresses.map<Widget>((String item) {
return Container(
child: Text(item),
);
}).toList();
},
style: TextStyle(
fontSize: 1.9 *
SizeConfig.textMultiplier,
color:
Theme.of(context).accentColor,
fontFamily: 'Montserrat'),
value: _selectedShippingAddress,
isExpanded: true,
underline: Container(
height: 1,
color: Theme.of(context)
.textSelectionColor,
),
icon: Icon(Icons.arrow_drop_down),
isDense: true,
),
)
So what is a solution for this? Can anyone help on this?
From the example that you provided I replicated it and there is a problem in the blow code
DropdownMenuItem<String>(
value: value,
child: SizedBox(
height: 10 * SizeConfig.heightMultiplier,
Maybe the height is doing some problem just added a sample example below to let you know the things work.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SampleApp(),
debugShowCheckedModeBanner: false,
);
}
}
class SampleApp extends StatefulWidget {
#override
_SampleAppState createState() => _SampleAppState();
}
class _SampleAppState extends State<SampleApp> {
String _selectedShippingAddress;
List addresses = ['sample1', 'sample 2'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your heading'),
),
body: DropdownButtonHideUnderline(
child: DropdownButton<String>(
items: addresses.map((value) {
return new DropdownMenuItem<String>(
value: value,
child: SizedBox(
child: Column(
children: [
SizedBox(height: 5),
new Text(value, overflow: TextOverflow.clip),
SizedBox(height: 5),
],
),
),
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_selectedShippingAddress = newValue;
});
},
hint: Text("Select address"),
selectedItemBuilder: (BuildContext context) {
return addresses.map<Widget>((item) {
return Container(
child: Text(item),
);
}).toList();
},
style: TextStyle(
fontSize: 14,
color: Theme.of(context).accentColor,
fontFamily: 'Montserrat'),
value: _selectedShippingAddress,
isExpanded: true,
underline: Container(
height: 1,
color: Theme.of(context).textSelectionColor,
),
icon: Icon(Icons.arrow_drop_down),
isDense: true,
),
));
}
}