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.
CodePudding user response:
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(),
),
]
],
),
),
),
);
}
}
CodePudding user response:
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 ValueNotifier
s and ValueListenableBuilder
s to update your UI only where it's needed.
CodePudding user response:
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,
CodePudding user response:
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(),
),
],
),
),
),
);
}
}