I am new to flutter, and am trying to create a dropdown box where the user can select multiple options or something similar to a dropdown box. The only thing I have found on the internet is multiselect, but I can't get it to work.
I have tried making it the only child in my widget tree and also I have tried switching the versioning around in my pubsec.yaml file to no avail.
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_multiselect/flutter_multiselect.dart';
//void main() => runApp(MaterialApp(Choices()));
Future<Null> main() async {
runApp(
MaterialApp(
title: "multiselect help",
debugShowCheckedModeBanner: false,
initialRoute: 'Choices',
routes: {
'Choices': (BuildContext context) => Choices(),
},
),
);
}
class Choices extends StatefulWidget {
Choices({Key key}) : super(key: key);
#override
_ChoicesState createState() => _ChoicesState();
}
class _ChoicesState extends State<Choices> {
String _value;
String _value2;
String _value3;
List _myActivities = [];
String _myActivitiesResult = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Row(
children: <Widget>[
/* DropdownButton<String>(
items: [
DropdownMenuItem(
value: "1",
child: Text("1"),
),
DropdownMenuItem(
value: "2",
child: Text("2"),
),
],
onChanged: (value) {
setState(() {
_value = value;
});
},
hint: Text("Item"),
value: _value,
),
DropdownButton<String>(
items: [
DropdownMenuItem(
value: "1",
child: Text("1"),
),
DropdownMenuItem(
value: "2",
child: Text("2"),
),
DropdownMenuItem(
value: "3",
child: Text("3"),
),
DropdownMenuItem(
value: "4",
child: Text("4"),
),
],
onChanged: (value) {
setState(() {
_value2 = value;
});
},
//new code
hint: Text("#"),
value: _value2,
),
*/
MultiSelect(
autovalidate: false,
titleText: "hi",
validator: (value) {
if (value == null) {
return 'Please select one or more option(s)';
}
},
errorText: 'Please select one or more option(s)',
dataSource: [
{
"display": "Australia",
"value": 1,
},
{
"display": "Canada",
"value": 2,
},
{
"display": "India",
"value": 3,
},
{
"display": "United States",
"value": 4,
}
],
textField: 'display',
valueField: 'value',
filterable: true,
required: true,
value: null,
onSaved: (value) {
print('The value is $value');
}
),
],
),
),
),
);
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Next Page"),
),
body: Choices()
);
}
In the expected results I would have a dropdown or something similar where I can make multiple selections. The actual results show nothing, including not even showing the brother/sister widgets when they are not commented out. Thanks for your help!
When dealing with Row, layouts can sometimes end up with an infinite width, which is what's happening here. Luckily, the solution is simple. Just wrap the MultiSelect widget in the Expanded widget, and it will constrain the MultiSelect to only use the available width, and no more.
So
MultiSelect(...),
becomes
Expanded(
child: MultiSelect(...),
),
Alternatively, you can remove the Row entirely and just put MultiSelect as a single Widget.
Related
Am trying to select one or more check boxes from a list of check boxes, i have found that the best option is using the checkBoxListTile widget to implement this.
First i have defined a list and used the widget as follows:
List<String> _texts = ["google.com", "youtube.com", "yahoo.com", "gmail.com"];
Expanded(
child: ListView(
children: _texts
.map((text) => CheckboxListTile(
title: Text(text),
value: _isChecked,
onChanged: (val) {
setState(() {
_isChecked = val;
});
},
))
.toList(),
),
),
check boxes are displayed fine but whenever i click one checkbox all are checked, how can i handle choosing one or more check boxes from the list?
Thank you
Try below code hope its help to you I have try it other way
Only Single Checkbox Selected:
Your List :
List _texts = [
{
"value": false,
"site": "google.com",
},
{
"value": false,
"site": "youtube.com",
},
{
"value": false,
"site": "yahoo.com",
},
{
"value": false,
"site": "gmail.com",
},
];
Your Widget:
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 64.0),
child: Column(
children: List.generate(
_texts.length,
(index) => CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
dense: true,
title: Text(
_texts[index]["site"],
style: const TextStyle(
fontSize: 16.0,
color: Colors.black,
),
),
value: _texts[index]["value"],
onChanged: (value) {
setState(() {
for (var element in _texts) {
element["value"] = false;
}
_texts[index]["value"] = value;
});
},
),
),
),
),
Full Code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Flutter Single Checkbox Example"),
),
body: SafeArea(
child: Center(
child: CheckboxWidget(),
))),
);
}
}
class CheckboxWidget extends StatefulWidget {
#override
CheckboxWidgetState createState() => new CheckboxWidgetState();
}
class CheckboxWidgetState extends State {
List _texts = [
{
"value": false,
"site": "google.com",
},
{
"value": false,
"site": "youtube.com",
},
{
"value": false,
"site": "yahoo.com",
},
{
"value": false,
"site": "gmail.com",
},
];
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 64.0),
child: Column(
children: List.generate(
_texts.length,
(index) => CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
dense: true,
title: Text(
_texts[index]["site"],
style: const TextStyle(
fontSize: 16.0,
color: Colors.black,
),
),
value: _texts[index]["value"],
onChanged: (value) {
setState(() {
for (var element in _texts) {
element["value"] = false;
}
_texts[index]["value"] = value;
});
},
),
),
),
);
}
}
Result Screen->
Multiple Checkbox Selection
Your List/Map
Map<String, bool> values = {
'google.com': false,
'youtube.com': false,
'yahoo.com': false,
'gmail.com': false,
};
Your Function:
var tmpArray = [];
getCheckboxItems() {
values.forEach((key, value) {
if (value == true) {
tmpArray.add(key);
}
});
print(tmpArray);
tmpArray.clear();
}
Your Widget:
Column(
children: <Widget>[
ListView(
shrinkWrap: true,
children: values.keys.map((String key) {
return new CheckboxListTile(
title: new Text(key),
value: values[key],
onChanged: (value) {
setState(() {
values[key] = value!;
});
},
);
}).toList(),
),
const SizedBox(
height: 100,
),
ElevatedButton(
child: Text(
" Checkbox Items ",
style: TextStyle(fontSize: 18),
),
onPressed: getCheckboxItems,
),
],
)
Full Example
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Flutter Multiple Checkbox Example"),
),
body: SafeArea(
child: Center(
child: CheckboxWidget(),
))),
);
}
}
class CheckboxWidget extends StatefulWidget {
#override
CheckboxWidgetState createState() => new CheckboxWidgetState();
}
class CheckboxWidgetState extends State {
Map<String, bool> values = {
'google.com': false,
'youtube.com': false,
'yahoo.com': false,
'gmail.com': false,
};
var tmpArray = [];
getCheckboxItems() {
values.forEach((key, value) {
if (value == true) {
tmpArray.add(key);
}
});
print(tmpArray);
tmpArray.clear();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListView(
shrinkWrap: true,
children: values.keys.map((String key) {
return new CheckboxListTile(
title: new Text(key),
value: values[key],
onChanged: (value) {
setState(() {
values[key] = value!;
});
},
);
}).toList(),
),
const SizedBox(
height: 100,
),
ElevatedButton(
child: Text(
" Checkbox Items ",
style: TextStyle(fontSize: 18),
),
onPressed: getCheckboxItems,
),
],
);
}
}
Result Screen->
Refer Video Tutorial for Flutter Multiselect Dropdown Checkbox on YouTube
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: _title,
home: CheckBoxExample(),
);
}
}
class CheckBoxExample extends StatefulWidget {
const CheckBoxExample({Key? key}) : super(key: key);
#override
State<CheckBoxExample> createState() => _CheckBoxExampleState();
}
class _CheckBoxExampleState extends State<CheckBoxExample> {
String selectedMonth = "";
List checkListItems = [
{
"id": 0,
"value": false,
"monthName": "January",
},
{
"id": 1,
"value": false,
"monthName": "Febuary",
},
{
"id": 2,
"value": false,
"monthName": "March",
},
{
"id": 3,
"value": false,
"monthName": "April",
},
{
"id": 4,
"value": false,
"monthName": "May",
},
{
"id": 5,
"value": false,
"monthName": "June",
},
{
"id": 6,
"value": false,
"monthName": "July",
},
{
"id": 7,
"value": false,
"monthName": "August",
},
{
"id": 8,
"value": false,
"monthName": "September",
},
{
"id": 9,
"value": false,
"monthName": "October",
},
{
"id": 10,
"value": false,
"monthName": "November",
},
{
"id": 11,
"value": false,
"monthName": "December",
},
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 64.0),
child: Column(
children: [
Text(
selectedMonth,
style: const TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 85.0),
Column(
children: List.generate(
checkListItems.length,
(index) => CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
dense: true,
title: Text(
checkListItems[index]["monthName"],
style: const TextStyle(
fontSize: 16.0,
color: Colors.black,
),
),
value: checkListItems[index]["value"],
onChanged: (value) {
setState(() {
for (var element in checkListItems) {
element["value"] = false;
}
checkListItems[index]["value"] = value;
selectedMonth ="${checkListItems[index]["id"]+1}, ${checkListItems[index]["monthName"]}";
});
},
),
),
),
],
),
),
);
}
}
Output
The value parameter for in CheckboxListTile is how widget knows whether checkbox is checked or not. When you give all of them same value, all of their state changes.
You can keep a seperate list to keep track of if the specific checkbox is checked.
I am creating a form with the plugin flutter_form_builder (https://pub.dev/packages/flutter_form_builder).
When I use FormBuilderDropdown, you can selected a different value, but it won't show you the selected value on screen. Normally you have a value property, but this widget does not have that. It only has an initial value.
Note
When I removed the whole onChanged method, it does show me the right value on the screen. BUT I need this onChanged method so I cannot remove it...
Code from
final shippingPackagesList = [
{"key": "dhlpwc-parcelshop", "label": "DHL ServicePoint"},
{"key": "dhlpwc-home", "label": "Thuis bezorgen"},
{
"key": "local_pickup:7",
"label": "Afhalen in de winkel in Heerlen, Limburg"
},
];
return Column(
children: [
FormBuilder(
autovalidateMode: AutovalidateMode.always,
key: _formKey,
child: Column(
children: [
const SizedBox(height: 5.0),
FormBuilderDropdown(
items: shippingPackagesList
.map((shippingPackage) =>
DropdownMenuItem(
value: shippingPackage['key'],
child: Text(shippingPackage['label']!),
))
.toList(),
name: 'shipping_key',
onChanged: (value) {
String shippingPackageKey =
value.toString();
// Set selected shipping method in cart view model
cartViewModel
.setSelectedShippingPackageByString(
shippingPackageKey);
cartViewModel.updateTotalCosts();
},
// initialValue: "dhlpwc-parcelshop",
hint: Text("Kies verzendmethode"),
decoration: const InputDecoration(
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.zero)),
contentPadding: EdgeInsets.all(8.0),
)),
const SizedBox(height: 10.0),
],
)),
Text(
'€ ${cartViewModel.selectedShippingPackage!.totalCost.toStringAsFixed(2)}',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
]
)
How can I solve this problem? Or is this a bug?
EDIT
Cart view model functions
class CartViewModel extends ChangeNotifier {
// Properties
ShippingPackage? _selectedShippingPackage;
double? _totalWithShippingPrice;
// Getters
ShippingPackage? get selectedShippingPackage => _selectedShippingPackage;
double? get totalWithShippingPrice => _totalWithShippingPrice;
void setSelectedShippingPackageByString(String shippingPackageKey) {
for (var shippingPackage in cart!.shippingPackages) {
if (shippingPackage.key == shippingPackageKey) {
_selectedShippingPackage = shippingPackage;
}
}
notifyListeners();
}
void updateTotalCosts() {
double total =
cart!.totals.articlesWithTax + selectedShippingPackage!.totalCost;
_totalWithShippingPrice = total;
notifyListeners();
}
}
Main
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CartViewModel()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'App',
home: Scaffold(
body: MyMainHome(),
),
),
);
}
Pubspec yaml
add provider: ^6.0.2 in pubspec.yaml
I experimented with the flutter_form_builder and the FormBuilderDropdown specifically. Writing this code based on the example of the package:
class Home72124205 extends StatefulWidget {
const Home72124205({Key? key}) : super(key: key);
#override
State<Home72124205> createState() => _Home72124205State();
}
class _Home72124205State extends State<Home72124205> {
List<String> locationsList = [
'New York',
'Tokyo',
'London',
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FormBuilderDropdown(
name: 'location',
decoration: const InputDecoration(
labelText: 'Location',
),
initialValue: locationsList.first,
allowClear: true,
onChanged: (value){
print(value);
},
items: locationsList
.map((location) => DropdownMenuItem(
value: location,
child: Text(location),
)).toList(),
),
),
);
}
}
I was not able to reproduce your issue. The widget works as intended. The label on the dropdown changes, the onChange gets called and the code gets executed.
As we don't have access to your full application, I am unable debug your issue.
Are you able to experiment with this example and test if, within the context of your application, the problem still happens?
I am having some trouble when setting up my dropdown functionality. I do not understand why is this since the widget itself accepts String: DropdownMenuItem
I get the error:
type string is not a subtype of type DropdownMenuItem<dynamic>
I tried either to cast my value to String or dynamic like this:
value: map["breed"].cast() or
value: map["breed"].cast()
but nothing seems to work.
class DogForm extends StatefulWidget {
#override
_DogFormState createState() => _DogFormState();
}
class _DogFormState extends State<DogForm> {
final todoController = TextEditingController();
final List<DropdownMenuItem> breeds = [];
String? _mySelection = '';
final List<Map> _mybreedJson = [
{
"breed": "Cavalier King Charles Spaniel",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/CarterBIS.Tiki.13.6.09.jpg/220px-CarterBIS.Tiki.13.6.09.jpg"
},
{
"breed": "Curly-Coated Retriever",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Curly_Coated_Retriever.jpg/220px-Curly_Coated_Retriever.jpg"
},
];
void addToDo() async {
if (todoController.text.trim().isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Empty title"),
duration: Duration(seconds: 2),
));
return;
}
await saveTodo(todoController.text);
setState(() {
todoController.clear();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Parse Todo List"),
backgroundColor: Colors.blueAccent,
centerTitle: true,
),
body: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(17.0, 1.0, 7.0, 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
isDense: true,
hint: Text('Select Breed'),
value: _mySelection,
onChanged: (String? newValue) {
setState(() {
_mySelection = newValue;
});
},
items: _mybreedJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["breed"],
// value: _mySelection,
child: Row(
children: <Widget>[
Image.asset(
map["img"],
width: 25,
),
Container(
margin: EdgeInsets.only(left: 10),
child: Text(map["breed"])),
],
),
);
}).toList(),
),
),
),
),
]),
)
],
));
}
}
Future<void> saveTodo(String title) async {
await Future.delayed(Duration(seconds: 1), () {});
final todo = ParseObject('Todo')
..set('title', title)
..set('done', false);
await todo.save();
}
Please! can somebody tell me how to make it work with a list like this?
_mybreedJson = [
{
"breed": "Cavalier King Charles Spaniel",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/CarterBIS.Tiki.13.6.09.jpg/220px-CarterBIS.Tiki.13.6.09.jpg"
},
{
"breed": "Curly-Coated Retriever",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Curly_Coated_Retriever.jpg/220px-Curly_Coated_Retriever.jpg"
},
];
This is what you want ?, please run codes. I changed .asset => .network and , I put real value as default value
import 'package:flutter/material.dart';
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
theme: ThemeData.dark(),
home: DogForm(),
);
}
}
class DogForm extends StatefulWidget {
#override
_DogFormState createState() => _DogFormState();
}
class _DogFormState extends State<DogForm> {
final todoController = TextEditingController();
final List<DropdownMenuItem> breeds = [];
String? _mySelection = 'Cavalier King Charles Spaniel';
final List<Map> _mybreedJson = [
{
"breed": "Cavalier King Charles Spaniel",
"img":
"https://images.pexels.com/photos/45201/kitty-cat-kitten-pet-45201.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
},
{
"breed": "Curly-Coated Retriever",
"img":
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSjiLOiEP-qSR6OgMrPELypnHToVToGPEc_qTkuLq5mMKwCCMoQ4x6Fsn19uvBoDO0qZaQ&usqp=CAU"
},
];
void addToDo() async {
if (todoController.text.trim().isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("Empty title"),
duration: Duration(seconds: 2),
));
return;
}
await saveTodo(todoController.text);
setState(() {
todoController.clear();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Parse Todo List"),
backgroundColor: Colors.blueAccent,
centerTitle: true,
),
body: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.fromLTRB(17.0, 1.0, 7.0, 1.0),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Expanded(
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
isDense: true,
hint: const Text('Select Breed'),
value: _mySelection,
onChanged: (String? newValue) {
setState(() {
_mySelection = newValue;
});
},
items: _mybreedJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["breed"],
// value: _mySelection,
child: Row(
children: <Widget>[
Image.network(
map["img"],
width: 25,
),
Container(margin: const EdgeInsets.only(left: 10), child: Text(map["breed"])),
],
),
);
}).toList(),
),
),
),
),
]),
)
],
));
}
}
Future<void> saveTodo(String title) async {
await Future.delayed(const Duration(seconds: 1), () {});
final todo = ParseObject('Todo')
..set('title', title)
..set('done', false);
await todo.save();
}
If you make Map map --> Map<String,String> map, maybe flutter show you where error is.
I'm trying to "close" the BLoC state. I'm basically trying to dispose the state.
Here's how my app looks like.
When I click on the "Add" TextButton, it shows an alert dialog saying that the form must be filled to proceed. When I fill the form, it generates a code and it works like a charm. Even though the debug console shows me an error that it tried calling the "close" method, but there was no such method. Any ideas how to fix it?
Code:
import 'dart:io';
import 'package:duckie/blocs/manual_input/manual_input_bloc.dart';
import 'package:duckie/screens/widgets/alert_dialog.dart';
import 'package:duckie/screens/widgets/custom_text_field.dart';
import 'package:duckie/shared/text_styles.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ManualInputScreen extends StatefulWidget {
#override
_ManualInputScreenState createState() => _ManualInputScreenState();
}
class _ManualInputScreenState extends State<ManualInputScreen> {
String secretKey;
String issuer;
String accountName;
String numberOfDigits = '6';
String timeStep = '30';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'manual-input',
style: TextStyles.appBarText,
).tr(),
centerTitle: true,
elevation: 0.0,
actions: [
BlocConsumer<ManualInputBloc, ManualInputState>(
listener: (context, state) {
if (state is ManualInputError) {
Platform.isAndroid
? CustomAlertDialog.showAndroidAlertDialog(
context,
state.alertDialogErrorTitle,
state.alertDialogErrorContent)
: CustomAlertDialog.showIosAlertDialog(
context,
state.alertDialogErrorTitle,
state.alertDialogErrorContent);
}
ManualInputBloc manualInputBloc;
manualInputBloc.close();
},
builder: (context, state) {
if (state is ManualInputInitial || state is ManualInputFinal) {
return TextButton(
onPressed: () {
BlocProvider.of<ManualInputBloc>(context).add(
GetFormTextEvent(secretKey, issuer, accountName,
numberOfDigits, timeStep));
},
child: Text('add').tr(),
);
}
return TextButton(
onPressed: () {},
child: Text('add').tr(),
);
},
)
],
),
body: Container(
padding: EdgeInsets.all(8.0),
child: ListView(
children: [
CustomTextField(
labelText: 'secret-key'.tr(),
onChanged: (value) {
setState(() {
secretKey = value;
});
},
),
SizedBox(
height: 8.0,
),
CustomTextField(
labelText: 'issuer'.tr(),
onChanged: (value) {
issuer = value;
},
),
SizedBox(
height: 8.0,
),
CustomTextField(
labelText: 'account-name'.tr(),
onChanged: (value) {
setState(() {
accountName = value;
});
},
),
SizedBox(
height: 8.0,
),
Platform.isAndroid
? ListBody(
children: [
Text('number-of-digits').tr(),
SizedBox(
height: 5.0,
),
DropdownButton(
value: numberOfDigits,
onChanged: (value) {
setState(() {
numberOfDigits = value;
});
},
items: [
DropdownMenuItem(
value: '6',
child: Text('6'),
),
DropdownMenuItem(
value: '8',
child: Text('8'),
),
],
)
],
)
: ListBody(
children: [
Text('number-of-digits').tr(),
SizedBox(
height: 5.0,
),
CupertinoSegmentedControl(
groupValue: numberOfDigits,
children: {
'6': Text('6'),
'8': Text('8'),
},
onValueChanged: (value) {
setState(() {
numberOfDigits = value;
});
},
),
],
),
SizedBox(
height: 8.0,
),
Platform.isAndroid
? ListBody(
children: [
Text('time-step').tr(),
SizedBox(
height: 5.0,
),
DropdownButton(
value: timeStep,
onChanged: (value) {
setState(() {
timeStep = value;
});
},
items: [
DropdownMenuItem(
value: '30',
child: Text('30'),
),
DropdownMenuItem(
value: '60',
child: Text('60'),
),
],
)
],
)
: ListBody(
children: [
Text('time-step').tr(),
SizedBox(
height: 5.0,
),
CupertinoSegmentedControl(
groupValue: timeStep,
children: {
'30': Text('30'),
'60': Text('60'),
},
onValueChanged: (value) {
setState(() {
timeStep = value;
});
},
),
],
),
],
),
),
);
}
}
The exact code that shows an error:
ManualInputBloc manualInputBloc;
manualInputBloc.close();
manual_input_bloc.dart
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:dart_otp/dart_otp.dart';
import 'package:meta/meta.dart';
part 'manual_input_event.dart';
part 'manual_input_state.dart';
class ManualInputBloc extends Bloc<ManualInputEvent, ManualInputState> {
ManualInputBloc() : super(ManualInputInitial());
#override
Stream<ManualInputState> mapEventToState(
ManualInputEvent event,
) async* {
if (event is GetFormTextEvent) {
if (event.secretKey == null ||
event.issuer == null ||
event.accountName == null) {
yield ManualInputError(
'all-fields-error-title', 'all-fields-error-content');
} else {
try {
final TOTP totp = TOTP(
secret: event.secretKey,
digits: int.parse(event.numberOfDigits),
interval: int.parse(event.timeStep),
);
final String otp = totp.now();
yield ManualInputFinal(
otp,
event.issuer,
event.accountName,
);
} catch (error) {
yield ManualInputError('totp-fail-title', 'totp-fail-content');
print(error.toString());
}
}
}
}
}
That’s because you’re not initialising manualinputBloc. In this context the bloc would be null.
You should initialise your variable first:
ManualInputBloc manualInputBloc = ManualInputBloc();
edit:
in the builder method of the bloc is also not an appropriate place to initiate or close the bloc. This is how you want to change your state class:
class _yourState extends State<YourState> {
ManualInputBloc manualInputBloc;
#override
void initState() {
manualInputBloc = ManualInputBloc();
manualInputBloc.add(YourEvent());
}
#override
void dispose() {
manualInputBloc.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return BlocBuilder<ManualInputBloc, ManualInputState>(
cubit: manualInputBloc,
builder: (context, state) {
return YourWidget();
}
}
First, you probably need to understand what BLOC is, what Events are and what States are.
You can not just close() bloc, because it does something on your screen.
States are things what application serves to the user. Your states should have names like: DisplayingForm, ValidatingForm, DisplayingError, DisplayingSuccess.
Events are things what user is clicking. Your events should have names like: AddDataEvent (you have only one so this is not crucial in your app)
Common flow is:
first state is DisplayingForm -> user clicks Add -> state changes to ValidatingForm then there is a fork -> on success DisplayingSuccess -> on error DisplayingError.
I you want to do something after success, for example close the window, then if(state is DisplayingSuccess) Navigator.pop(); or you can set some timer delay before pop();
or you can if(state is DisplayingSuccess) BlocProvider.of(context).add(ResetFormEvent), but you need to handle in your bloc an event ResetFormEvent which at the end will yield DisplayingForm state once again.
And you should communicate with bloc using .add(SomeEvent), not .close() method. Cubit is kind of bloc which enables to execute methods on it instead of events.
I want to reset DropdownButtonFormField. I mange to reset it by setting it's value null and using globalkey as following code.
Here, problem is that i need to click twice to reset it.
Note: I know using DropdownButton, we can reset more easily but my question is why DropdownButtonFormField is not resetting when i click first time.
After Update:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
String abc;
FocusNode _node = FocusNode();
GlobalKey<FormState> _key = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Form(
key: _key,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Focus(
focusNode: _node,
onFocusChange: (bool focus) {
setState(() {});
},
child: Listener(
onPointerDown: (_) {
FocusScope.of(context).requestFocus(_node);
},
child: DropdownButtonFormField(
hint: Text('select value'),
value: abc,
items: <String>['A', 'B', 'C', 'D'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String newValue) {
setState(() {
abc = newValue;
});
},
),
),
),
Text("value is $abc"),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
abc = null;
_key.currentState.reset();
});
},
tooltip: 'Reset',
child: Icon(Icons.clear),
)),
);
}
}
you may need to make manual Focus
you need to give the global key to form as well
FocusNode _node = FocusNode();
...
Focus(
focusNode: _node,
onFocusChange: (bool focus) {
setState(() {});
},
child: Listener(
onPointerDown: (_) {
FocusScope.of(context).requestFocus(_node);
},
child: DropdownButtonFormField(
iconSize: 50,
onChanged: (s) {
setState(() {
abc = s;
});
},
hint: Text(
'Select Text',
),
items: [
DropdownMenuItem(value: '1', child: Text('A')),
DropdownMenuItem(value: '2', child: Text('B')),
DropdownMenuItem(value: '3', child: Text('C')),
DropdownMenuItem(value: '4', child: Text('D')),
],
),
),
),
...
FloatingActionButton(
onPressed: () {
setState(() {
print("hello");
abc = null;
_key.currentState.reset();
});
// _flyIronMan();
},
child: Icon(Icons.add),
),