Using different widgets on the basis of value of spinner in flutter - flutter

I want the user on Register and Login screen to first choose their role from a drop down button and on the basis of its value I want to show further widgets on the very same page....
For this should i create a normal class containing all the respective widgets or a stateful widget?
and how to call that widget just after selecting the role from the DropDown List?

You can create different Stateful or stateless widget base on requirement for different role and you can change screen base on drop down value.
Following code will help you more.
class Delet2 extends StatefulWidget {
#override
_Delet2State createState() => _Delet2State();
}
class _Delet2State extends State<Delet2> {
Widget _currentScreen;
int role;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_currentScreen ?? Container(),
DropdownButton(
value: role,
items: [1, 2]
.map(
(item) => DropdownMenuItem(
value: item,
child: Text(
item.toString(),
),
),
)
.toList(),
onChanged: (value) {
setState(() {
role = value;
if (role == 1) {
_currentScreen = Screen1();
} else {
_currentScreen = Screen2();
}
});
},
),
],
),
),
);
}
}
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Text("screen1"),
);
}
}
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Text("screen2"),
);
}
}

You have to create Stateful widget and then based on the value selected in spinner you can draw widget, please follow below code snippet:
class MySpinnerWidget extends StatefulWidget {
#override
_MySpinnerWidgetWidgetState createState() => _MySpinnerWidgetWidgetState();
}
class _MySpinnerWidgetWidgetState extends State<MySpinnerWidget> {
String dropdownValue = 'One';
List<String> spinnerItems = ['One', 'Two', 'Three'];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(children: <Widget>[
DropdownButton<String>(
value: dropdownValue,
icon: Icon(Icons.arrow_drop_down),
onChanged: (String data) {
setState(() {
dropdownValue = data;
});
},
items: spinnerItems.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
if(dropdownValue == 'One')
Text('Value One selected from spinner'),
if(dropdownValue == 'Two')
Text('Value Two selected from spinner'),
if(dropdownValue == 'Three')
Text('Value Three selected from spinner'),
]),
),
);
}
}

Related

How to call a provider from a Hero widget - Flutter

I'm transferring an input form, from my "home" widget to a popup card (which opens with a Hero widget). One of the "dropdown" boxes in that form, contains names of users registered in a FireBase database.
Before the transferring, the forms are working just fine. however, after, when I click on the button which opens the popup card, the app freezes and I get this error:
Code for the main widget/stream provider here:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const Hyttekos());
}
class Hyttekos extends StatelessWidget {
const Hyttekos({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamProvider<MyUser?>.value(
initialData: null,
value: AuthService().user,
child: const MaterialApp(
home: Wrapper(),
),
);
}
}
Code for the widget looks like this:
class addActivityPopupCard extends StatefulWidget {
List<String> membersToShow = [];
addActivityPopupCard({required this.membersToShow});
#override
State<addActivityPopupCard> createState() => _addActivityPopupCardState();
}
class _addActivityPopupCardState extends State<addActivityPopupCard> {
dynamic _dropDownActivity;
String? _dropDownMember;
List<String> activities = [
"Pil og Boge",
"Politisk Ukorrekt",
"Kortspel",
];
#override
Widget build(BuildContext context) {
var board = Provider.of<List<MyUser?>>(context);
List<MyUser?> members = [];
for (var user in board) {
members.add(user);
}
return Center(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Hero(
tag: _heroAddTag,
createRectTween: (begin, end) {
return RectTween(begin: begin, end: end);
},
child: Material(
color: Colors.white,
elevation: 2,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownButton<String>(
value: _dropDownActivity,
onChanged: _dropDownCallActivity,
items: activities.map((String value) {
return DropdownMenuItem(
value: value,
child: Text(value),
);
}).toList(),
),
// Members
Builder(builder: (context) {
return DropdownButton<String>(
value: _dropDownMember,
onChanged: _dropDownCallMember,
items: members.map((MyUser? value) {
return DropdownMenuItem(
value: value?.uid ?? "",
child: Text(value?.name ?? ""),
);
}).toList(),
);
}),
],
),
),
),
),
),
),
);
}
void _dropDownCallActivity(String? selectedValue) {
if (selectedValue is String) {
setState(() {
_dropDownActivity = selectedValue;
});
}
print(_dropDownActivity);
}
void _dropDownCallMember(String? selectedValue) {
if (selectedValue is String?) {
setState(() {
_dropDownMember = selectedValue;
});
}
print(_dropDownMember);
}
}
The problem is in your Hyttekos class
Read this link to use the correct format of the stream provider
https://pub.dev/packages/streams_provider
This must look like this
Widget build(BuildContext context) {
return StreamProvider<MyUser?>.value(
initialData: null,
value: AuthService().user,
builder: (context, child) {
// return widget here based on selector stream emits
},
);
}

How to generate multiple Dropdown dynamically in Flutter?

I have a Java background and new to Flutter. I have stuck in a scenario where I need to create multiple dropdown dynamically. For instance, There is a Pizza deal offers 2 Large pizza, 2 Small pizza and 1 drink. So, Whenever customer select any pizza He/She must need to select a flavor to it. If there is 2 Large pizza what i need to generate is 2 dropdown list with defined flavor so that customer can select 2 different flavor and want to save them in separate variable so that, I can get the value later on, and the same goes for 2 small pizza. In this deal, I have to create 5 dropdown and the quantity of dropdown varies along the deal they offer. How can I achieve this in Flutter?
You can copy paste run full code below
You can use ListView, when add data to List like List<CartItem>, DropdownButton will show
You can for loop List<CartItem> to summary data you need like quantity
code snippet
class _CartWidgetState extends State<CartWidget> {
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(child: Pizza(cartItem: widget.cart[widget.index])),
Expanded(child: Flavor(cartItem: widget.cart[widget.index])),
Expanded(
child: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
print(widget.index);
widget.cart.removeAt(widget.index);
widget.callback();
});
...
ListView.builder(
key: UniqueKey(),
itemCount: cart.length,
itemBuilder: (BuildContext ctxt, int index) {
return CartWidget(
cart: cart, index: index, callback: refresh);
}),
output of working demo when click print button
I/flutter (14508): Pizza 1
I/flutter (14508): Pizza 2
I/flutter (14508): Pizza 4
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class Flavor extends StatefulWidget {
CartItem cartItem;
Flavor({this.cartItem});
#override
_FlavorState createState() => _FlavorState();
}
class _FlavorState extends State<Flavor> {
String _value = "Flavor 1";
#override
void initState() {
super.initState();
_value = widget.cartItem.flavor;
}
#override
void didUpdateWidget(Flavor oldWidget) {
if (oldWidget.cartItem.flavor != widget.cartItem.flavor) {
_value = widget.cartItem.flavor;
}
super.didUpdateWidget(oldWidget);
}
#override
Widget build(BuildContext context) {
return Container(
child: DropdownButton(
value: _value,
items: [
DropdownMenuItem(
child: Text("Flavor 1"),
value: "Flavor 1",
),
DropdownMenuItem(
child: Text("Flavor 2"),
value: "Flavor 2",
),
DropdownMenuItem(child: Text("Flavor 3"), value: "Flavor 3"),
DropdownMenuItem(child: Text("Flavor 4"), value: "Flavor 4")
],
onChanged: (value) {
setState(() {
_value = value;
widget.cartItem.flavor = value;
});
}),
);
}
}
class Pizza extends StatefulWidget {
CartItem cartItem;
Pizza({this.cartItem});
#override
_PizzaState createState() => _PizzaState();
}
class _PizzaState extends State<Pizza> {
String _value = "";
#override
void initState() {
super.initState();
_value = widget.cartItem.itemName;
}
#override
void didUpdateWidget(Pizza oldWidget) {
if (oldWidget.cartItem.itemName != widget.cartItem.itemName) {
_value = widget.cartItem.itemName;
}
super.didUpdateWidget(oldWidget);
}
#override
Widget build(BuildContext context) {
return Container(
child: DropdownButton(
value: _value,
items: [
DropdownMenuItem(
child: Text("Pizza 1"),
value: "Pizza 1",
),
DropdownMenuItem(
child: Text("Pizza 2"),
value: "Pizza 2",
),
DropdownMenuItem(child: Text("Pizza 3"), value: "Pizza 3"),
DropdownMenuItem(child: Text("Pizza 4"), value: "Pizza 4")
],
onChanged: (value) {
setState(() {
_value = value;
widget.cartItem.itemName = value;
});
}),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class CartItem {
String productType;
String itemName;
String flavor;
CartItem({this.productType, this.itemName, this.flavor});
}
class CartWidget extends StatefulWidget {
List<CartItem> cart;
int index;
VoidCallback callback;
CartWidget({this.cart, this.index, this.callback});
#override
_CartWidgetState createState() => _CartWidgetState();
}
class _CartWidgetState extends State<CartWidget> {
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(child: Pizza(cartItem: widget.cart[widget.index])),
Expanded(child: Flavor(cartItem: widget.cart[widget.index])),
Expanded(
child: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
print(widget.index);
widget.cart.removeAt(widget.index);
widget.callback();
});
},
),
)
],
);
}
}
class _MyHomePageState extends State<MyHomePage> {
List<CartItem> cart = [];
void refresh() {
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListView.builder(
key: UniqueKey(),
itemCount: cart.length,
itemBuilder: (BuildContext ctxt, int index) {
return CartWidget(
cart: cart, index: index, callback: refresh);
}),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RaisedButton(
onPressed: () {
cart.add(CartItem(
productType: "pizza",
itemName: "Pizza 1",
flavor: "Flavor 1"));
setState(() {});
},
child: Text("add Pizza"),
),
RaisedButton(
onPressed: () {
for (int i = 0; i < cart.length; i++) {
print(cart[i].itemName);
}
},
child: Text("Print Pizza"),
),
],
)
],
),
),
);
}
}
You can use collection-if in your UI code to show those dropdowns when a certain condition is met.
Widget build() {
return Column(
children: [
pizzaSelector(),
if (pizzaIsSelected)
flavorSelector(),
]
);
}
Andrea has a good video explaining collection-if and spread operators which I think will help you.

How can I change DropdownButton values from another widget in Flutter?

I am using that DropdownButton inside of the Stateless wigdet but I want to change that DropdownButton values from another Stateful widget. Likewise with using DropdownButton value, I want to change another stateless widget's container color.
Here is my First Stateless widget
List<String> dropdownValues = ['red', 'green', 'blue'];
#override
Widget build(BuildContext context) {
return Container(
child: DropdownButton(
items: dropdownValues
.map((value) => DropdownMenuItem(
child: Text(value),
value: value,
))
.toList(),
onChanged: (String newValue) {},
isExpanded: false,
hint: Text('Chose Color'),
selectedItemBuilder: ,
),
);
}
}
This is my Stateful widget
bool isLightOn = false;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
padding: new EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
LightBulb(
isLightOn: isLightOn,
),
LightButton(
isLightOn: isLightOn,
onButtonPress: onButtonPress,
),
LightColorSelector(),
],
),
);
}
void onButtonPress() {
if (isLightOn == false) {
setState(() {
isLightOn = true;
});
} else {
setState(() {
isLightOn = false;
});
}
}
}
How can I handle these problems and how can I manipulate DropdownButton values?
Likewise, I want to reflect that DropdownButton value with changing LightBulb's container color.
Here is LightBulb class
final bool isLightOn;
LightBulb({this.isLightOn});
#override
Widget build(BuildContext context) {
return Container(
color: isLightOn == false ? Colors.red : Colors.green,
padding: EdgeInsets.all(5.0),
child: isLightOn == false ? Text("OFF") : Text("ON"),
);
}
}
Here is a full working example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> dropdownValues = ['red', 'green', 'blue'];
String selected;
Color color;
#override
Widget build(BuildContext context) {
return Material(
child: Column(children: <Widget>[
DropdownButton<String>(
items: dropdownValues
.map((value) => DropdownMenuItem(
child: Text(value),
value: value,
))
.toList(),
onChanged: (String newValue) {
setState(() {
selected = newValue;
if (newValue == "red") color = Colors.red;
if (newValue == "green") color = Colors.green;
if (newValue == "blue") color = Colors.blue;
});
},
//isExpanded: false,
hint: Text('Chose Color'),
//selectedItemBuilder: ,
),
Container(
color: color != null ? color : Colors.black,
padding: EdgeInsets.all(5.0),
child: selected != null ? Text(selected) : Text("OFF", style: TextStyle(color: Colors.white)),
)
]),
);
}
}

Change DropdownButtonFormField value programmatically

I'm trying to change the DropdownButtonFormField value on event (button press for example) using setState. But it's not working.
Note: it works in case I use DropdownButton, but with DropdownButtonFormField it's not responding.
Here is a simple code showing what I'm trying to implement.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Testing(),
);
}
}
class Testing extends StatefulWidget {
#override
_TestingState createState() => _TestingState();
}
class _TestingState extends State<Testing> {
String selectedValue;
#override
Widget build(BuildContext context) {
return Material(
child: Column(
children: <Widget>[
DropdownButtonFormField(
value: selectedValue,
items: ['one', 'two'].map((value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedValue = value;
});
},
),
RaisedButton(
child: Text('test'),
onPressed: (){
setState(() {
selectedValue = 'two';
});
},
),
],
),
);
}
}
Define instance variable from Global Key and pass it to DropdownButtonFormField
final dropdownState = GlobalKey<FormFieldState>();
You can change the value of dropDownFieldItem by calling this method
dropdownState.currentState.didChange('two');
final code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Testing(),
);
}
}
class Testing extends StatefulWidget {
#override
_TestingState createState() => _TestingState();
}
class _TestingState extends State<Testing> {
String selectedValue;
final dropdownState = GlobalKey<FormFieldState>();
#override
Widget build(BuildContext context) {
return Material(
child: Column(
children: <Widget>[
DropdownButtonFormField(
key: dropdownState,
value: selectedValue,
items: ['one', 'two'].map((value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedValue = value;
});
},
),
RaisedButton(
child: Text('test'),
onPressed: () {
dropdownState.currentState.didChange('one');
},
),
],
),
);
}
}
Here working normally with DropdownButtonFormField and DropdownButton.
flutter --version
Flutter 1.12.13+hotfix.9 • channel stable •
In Flutter version 1.17.2 that bug was fixed, so be sure to upgrade.
Github issue: https://github.com/flutter/flutter/issues/56898
Fixed in version 1.17.2: https://github.com/flutter/flutter/wiki/Hotfixes-to-the-Stable-Channel#1172-may-28-2020

Set value of Dropdown Button manually

I have two widgets which are siblings in a container. One widget is a custom DropdownButton, the other one is a custom IconButton:
Parent widget:
static int _currentValue = 0;
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: GCWDropDownButton(
onChanged: (value) {
setState(() {
_currentValue = value;
});
}
),
),
GCWIconButton(
iconData: Icons.add,
onPressed: () {
print(_currentValue);
setState(() {
_currentValue++;
// <------------- how to set value to Dropdown Button
});
},
),
],
);
}
Dropdown widget:
class GCWDropDownButton extends StatefulWidget {
final Function onChanged;
const GCWDropDownButton({Key key, this.onChanged}) : super(key: key);
#override
_GCWDropDownButtonState createState() => _GCWDropDownButtonState();
}
class _GCWDropDownButtonState extends State<GCWDropDownButton> {
int _dropdownValue = 1;
#override
Widget build(BuildContext context) {
return Container(
child: DropdownButton(
value:_dropdownValue,
icon: Icon(Icons.arrow_downward),
onChanged: (newValue) {
setState(() {
_dropdownValue = newValue;
widget.onChanged(newValue);
});
},
items: ...
),
);
}
}
I want to change the DropdownButton's value to be increased after pressing the IconButton. If it were a TextField I'd use a Controller.
But how can I achieve this with the Dropdown?
You're trying to store the same value in 2 different states: in a parent and in a child one. In your case, it's better to do that in parent's state and to pass current value to the child.
int _currentIndex;
#override
Widget build(BuildContext context) {
...
child: Row(
children: <Widget>[
Expanded(
child: GCWDropDownButton(
currentIndex: _currentIndex,
onChanged: (index) {
setState(() {
_currentIndex = index;
});
},
),
),
GCWIconButton(
iconData: Icons.add,
onPressed: () {
setState(() {
if (_currentIndex == null) {
_currentIndex = 0;
} else {
_currentIndex++;
}
});
},
),
],
)
...
class GCWDropDownButton extends StatefulWidget {
final Function onChanged;
final int currentIndex;
const GCWDropDownButton({Key key, this.onChanged, this.currentIndex}) : super(key: key);
#override
_GCWDropDownButtonState createState() => _GCWDropDownButtonState();
}
class _GCWDropDownButtonState extends State<GCWDropDownButton> {
#override
Widget build(BuildContext context) {
final values = ['one', 'two', 'three'];
final currentValue = widget.currentIndex == null
? null
: values[min(values.length - 1, widget.currentIndex)]; // Not going out of range
return Container(
child: DropdownButton(
value: currentValue,
icon: Icon(Icons.arrow_downward),
onChanged: (newValue) {
setState(() {
widget.onChanged(values.indexOf(newValue));
});
},
items: values.map((v) =>
DropdownMenuItem(
child: Text(v.toString()),
value: v,
key: Key(v.toString())
)
).toList()
),
);
}
}
Or it would be even better to place DropdownButton and GCWIconButton in one stateful widget, so both widgets share the same state:
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: GCWDropDownButton()
),
);
}
}
class GCWDropDownButton extends StatefulWidget {
#override
_GCWDropDownButtonState createState() => _GCWDropDownButtonState();
}
class _GCWDropDownButtonState extends State<GCWDropDownButton> {
int _currentIndex;
final values = ['one', 'two', 'three'];
#override
Widget build(BuildContext context) {
final currentValue = _currentIndex == null ? null : values[_currentIndex];
return Row(
children: <Widget>[
Expanded(
child:Container(
child: DropdownButton(
value: currentValue,
icon: Icon(Icons.arrow_downward),
onChanged: (newValue) {
setState(() {
_currentIndex = values.indexOf(newValue);
});
},
items: values.map((v) =>
DropdownMenuItem(
child: Text(v.toString()),
value: v,
key: Key(v.toString())
)
).toList()
),
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
if (_currentIndex == null) {
_currentIndex = 0;
} else
// Not going out of range
if (_currentIndex != values.length - 1) {
_currentIndex++;
}
});
},
),
],
);
}
}