I'd make use of StatefulWidget
to achieve what you need (if you're not using more advanced state management options). State would be helpful to track user's choices, as well as to decide whether to render a text field or another dropdown (or nothing at all).
I've added a complete working example below. Note that it does not follow best practices in a sense that you would probably want to split it up in separate small widgets for better composability (and readability). However, I've opted for quick-and-dirty approach to fit everything in one place.
Also note that you'd probably want to do some more processing once a user makes a choice. Here, I simply illustrate how to render different widgets based on a user's choice (or more generally, changes in StatefulWidget's
state). Hence, this example is used to highlight one principle only.
import 'package:flutter/material.dart';
void main() {
runApp(DropdownExample());
}
class DropdownExample extends StatefulWidget {
@override
_DropdownExampleState createState() => _DropdownExampleState();
}
class _DropdownExampleState extends State<DropdownExample> {
String type;
int optionId;
final items = [
{
"displayName": "Enter value",
"type": "string",
},
{
"displayName": "Source",
"type": "list",
"data": [
{"id": 1, "displayId": "MO"},
{"id": 2, "displayId": "AO"},
{"id": 3, "displayId": "OffNet"}
]
}
];
@override
Widget build(BuildContext context) {
Widget supporting = buildSupportingWidget();
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Dropdown Example")),
body: Center(
child: Container(
height: 600,
width: 300,
child: Row(
children: <Widget>[
buildMainDropdown(),
if (supporting != null) supporting,
],
),
),
),
),
);
}
Expanded buildMainDropdown() {
return Expanded(
child: DropdownButtonHideUnderline(
child: DropdownButton(
value: type,
hint: Text("Select a type"),
items: items
.map((json) => DropdownMenuItem(
child: Text(json["displayName"]), value: json["type"]))
.toList(),
onChanged: (newType) {
setState(() {
type = newType;
});
},
),
),
);
}
Widget buildSupportingWidget() {
if (type == "list") {
List<Map<String, Object>> options = items[1]["data"];
return Expanded(
child: DropdownButtonHideUnderline(
child: DropdownButton(
value: optionId,
hint: Text("Select an entry"),
items: options
.map((option) => DropdownMenuItem(
child: Text(option["displayId"]), value: option["id"]))
.toList(),
onChanged: (newId) => setState(() {
this.optionId = newId;
}),
),
),
);
} else if (type == "string") {
return Expanded(child: TextFormField());
}
return null;
}