DropdownMenuItems are not rebuilding flutter using DropdownButton2 - flutter

My dropdown list has a multi-select feature. I have shown the list and selected Items are saved in an array called selectedClassList. Basically, it's a normal checkbox procedure.
But in the scenario of clicking a value called "any", I need to unselect all other items and need to mark "Any" as selected. The same is for other items, when a user clicks any of the other items, then item "any" should get unselected.
My code is like
DropdownButtonFormField2<dynamic>(
itemHeight: 40,
dropdownOverButton: false,
buttonWidth: double.infinity,
selectedItemHighlightColor: Colors.grey.shade300,
isExpanded: true,
value: widget.value,
dropdownElevation: 0,
itemPadding: const EdgeInsets.only(left: 15),
buttonDecoration: BoxDecoration(
border: Border.all(color: Colors.black87, width: 1),
borderRadius: BorderRadius.circular(5),
),
decoration: const InputDecoration.collapsed(
hintText: '',
border: InputBorder.none,
),
isDense: true,
offset: const Offset(0, -2),
iconSize: 20,
buttonHeight: 50,
buttonPadding: const EdgeInsets.only(left: 15, right: 10),
focusColor: const Color(0xffFFFFFF),
hint: const Text('Select One',
style: TextStyle(
fontSize: 14,
fontFamily: 'Poppins, Regular',
color: Color(0xffAAAAAA))),
style: const TextStyle(
fontSize: 14,
fontFamily: 'Poppins, Regular',
overflow: TextOverflow.ellipsis,
color: Color(0xff121212)),
iconOnClick: AnimatedRotation(
turns: 0.5,
duration: const Duration(milliseconds: 300),
child: Icon(Icons.arrow_down),
),
icon: AnimatedRotation(
turns: 1,
duration: const Duration(milliseconds: 300),
child: Icon(Icons.arrow_up),
),
dropdownDecoration: BoxDecoration(
border: Border.all(
color: Colors.black45,
width: 1,
),
borderRadius: const BorderRadius.all(Radius.circular(5)),
shape: BoxShape.rectangle),
dropdownMaxHeight: 200,
items: getClassDetails.data?.map((item) {
return DropdownMenuItem<dynamic>(
value: item,
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
var _isSelected = selectedClass!
.where((element) =>
element.settingName == item.settingName)
.toList()
.isNotEmpty;
return InkWell(
onTap: () {
if (item.settingName == "Any") {
selectedClass!.clear();
}
if (_isSelected == true) {
selectedClass!.remove(item);
} else {
selectedClass!.add(item);
}
setState(() {});
menuSetState(() {});
},
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item.settingName.toString(),
style: const TextStyle(
fontSize: 14,
fontFamily: 'Poppins, Regular',
color: Color(0xff121212)),
),
],
),
);
},
),
);
}).toList(),
)
I am not good at explaining things. Kindly let me know if I made any mistake.

Related

How to indent between DropdownButton and DropdownMenuItem in flutter

I am using DropdownButton and I am facing the following error. When opening the DropdownMenuItem list, I do not have an indent from the button itself. That is, I need to get the padding between the button (DropdownButton) and the dropdown list (DropdownMenuItem) so that there is a distance. But so far I haven't been able to do it. How can you make an indent between them?
code
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: List.generate(
widget.items.length,
(index) => DropdownMenuItem<String>(
value: widget.items[index],
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: StatefulBuilder(
builder: (context, setStateSB) => GFCheckboxListTile(
value: _selectedTitles.contains(widget.items[index]),
onChanged: (bool selected) {
_onItemSelect(selected, index);
setStateSB(() {});
},
selected: selected,
title: Text(
widget.items[index],
style: constants.Styles.smallTextStyleWhite,
),
padding: const EdgeInsets.only(top: 12, bottom: 13),
margin: const EdgeInsets.only(right: 0, left: 0),
size: 22,
activeBgColor: constants.Colors.greyCheckbox,
activeBorderColor: constants.Colors.greyXMiddle,
inactiveBgColor: constants.Colors.greyCheckbox,
activeIcon: SvgPicture.asset(constants.Assets.checkboxIcon),
inactiveBorderColor: constants.Colors.greyXMiddle,
type: type,
),
),
),
),
),
hint: _selectedTitles.length > 1
? const Text('Selecte EV',
style: constants.Styles.bigBookTextStyleWhite)
: Text(_selectedTitles.join().toString(),
style: constants.Styles.bigBookTextStyleWhite),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 185,
dropdownWidth: 140,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: constants.Colors.purpleMain,
),
color: constants.Colors.greyDark),
selectedItemBuilder: (context) {
return widget.items.map(
(item) {
return Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
Text(
item,
style: constants.Styles.bigBookTextStyleWhite,
),
],
);
},
).toList();
},
),
),
);
}
}
In the dropdown_button2 documentation, there is a property for moving the dropdown menu Offset. You can see it here https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/DropdownButton2/offset.html
On that property you just need to set an Offset, which is composed of an X and Y values.
In your case it would look something like this:
DropdownButton2(
offset: Offset(0,10),
...
),

Can i Select Multiple Accounts in a Banking app and pay them different amounts at the same time in flutter?

import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
import 'package:money_formatter/money_formatter.dart';
import 'package:shukela_app/api/banking_app_api.dart';
import 'package:shukela_app/screens/stokvel_detail.dart';
import 'package:shukela_app/screens/stokvels.dart';
import 'package:shukela_app/utils/constants.dart';
import 'package:shukela_app/utils/global_variables.dart';
import 'package:sizer/sizer.dart';
import 'package:shukela_app/model/bankingapp_model.dart';
import '../utils/user_preferences.dart';
class PayMultipleStokvelScreen extends StatefulWidget {
const PayMultipleStokvelScreen({Key? key}) : super(key: key);
#override
State<PayMultipleStokvelScreen> createState() =>
_PayMultipleStokvelScreenState();
}
TextEditingController txtSearch = TextEditingController();
TextEditingController txtAmount = TextEditingController();
class _PayMultipleStokvelScreenState extends State<PayMultipleStokvelScreen> {
String? selectedType;
bool hasText = false;
String buttonText = "PAY NOW";
bool isLoading = false;
Widget? showHideIcon() {
if (hasText) {
return IconButton(
icon: const Icon(
Icons.clear,
color: AppColors.primaryBlue,
),
onPressed: () {
txtSearch.clear();
setState(() {
hasText = false;
});
},
);
} else {
return null;
}
}
// void _showMultiSelectDialog(BuildContext context) async {
// await showDialog(
// context: context,
// builder: (ctx) {
// return MultiSelectDialog(
// items: _animals.map((e) => MultiSelectItem(e, e)).toList(),
// initialValue: _selectedAnimals,
// onConfirm: (values) {...},
// );
// },
// );
// }
double? balance;
final _formKey = GlobalKey<FormState>();
var selectedValue;
List<StokvelDetail> selectedStokvel = [];
#override
void initState() {
super.initState();
balance = double.parse(UserPreferences.getBalance() ?? '');
}
mf() {
MoneyFormatter mf = MoneyFormatter(amount: balance!);
return mf;
}
StokvelListState currentState = StokvelListState.showAllListState;
#override
Widget build(BuildContext context) => KeyboardDismisser(
gestures: const [GestureType.onTap],
child: SafeArea(
child: Scaffold(
backgroundColor: AppColors.secondaryColor,
appBar: AppBar(
backgroundColor: AppColors.secondaryColor,
elevation: 0,
title: const Text('Pay Multiple Stokvel',
style: screenTitleTextStyle),
leading: IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: AppColors.primaryBlue,
),
onPressed: () => Navigator.pop(context),
),
),
body: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 5.h),
Container(
height: 6.h,
width: 98.w,
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TypeAheadFormField<Stokvel?>(
debounceDuration: const Duration(milliseconds: 500),
hideSuggestionsOnKeyboardHide: false,
suggestionsBoxDecoration: const SuggestionsBoxDecoration(
constraints: BoxConstraints(maxHeight: 450),
color: AppColors.secondaryColor,
borderRadius: BorderRadius.all(Radius.circular(10))),
textFieldConfiguration: TextFieldConfiguration(
style: const TextStyle(
color: AppColors.primaryBlue,
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
controller: txtSearch,
onChanged: (value) {
setState(() {
hasText = true;
});
},
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.search,
color: AppColors.primaryBlue,
),
suffixIcon: showHideIcon(),
hintText: 'Search Stokvel',
border: const OutlineInputBorder(
borderSide:
BorderSide(color: AppColors.primaryBlue),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide:
const BorderSide(color: AppColors.primaryBlue),
),
),
),
validator: (val) {
if (val!.isEmpty) {
return "Please select stokvel";
}
return null;
},
suggestionsCallback: BankingAppApi.getStokvelSuggestions,
itemBuilder: (context, Stokvel? suggestion) {
final stokvel = suggestion!;
//
return ListTile(
trailing: SizedBox(
height: 20.0,
width: 20.0,
child: Container(
color: AppColors.primaryBlue,
),
),
title: Text(
stokvel.stokvelName!,
style: const TextStyle(
fontFamily: Fonts.primaryFont,
fontWeight: FontWeight.bold,
color: AppColors.primaryBlue,
),
),
subtitle: Text(
stokvel.stokvelType!,
style: const TextStyle(
fontFamily: Fonts.primaryFont,
fontWeight: FontWeight.bold,
color: AppColors.primaryBlue),
),
);
},
noItemsFoundBuilder: (context) => const SizedBox(
height: 60,
child: Center(
child: Text(
'No Stokvel Found.',
style: TextStyle(fontSize: 20),
),
),
),
onSuggestionSelected: (Stokvel? suggestion) {
final stokvel = suggestion!;
setState(() {
txtSearch.text = stokvel.stokvelName!;
hasText = true;
});
stokvelID = stokvel.stokvelID;
memberID = stokvel.memberID;
},
),
),
SizedBox(
height: 4.h,
),
SizedBox(height: 3.h),
Container(
height: 6.h,
width: 98.w,
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
controller: txtAmount,
decoration: const InputDecoration(
labelStyle: TextStyle(
color: AppColors.primaryBlue,
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
suffixText: "ZAR",
border: OutlineInputBorder(
borderSide:
BorderSide(color: AppColors.primaryBlue)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1, color: AppColors.primaryBlue),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1, color: AppColors.primaryBlue),
),
labelText: 'Amount',
contentPadding:
EdgeInsets.only(left: 20, right: 15, bottom: 8),
),
keyboardType: TextInputType.number,
style: const TextStyle(
fontSize: 20.0,
fontFamily: Fonts.primaryFont,
color: AppColors.primaryBlue),
validator: (val) {
if (val!.isEmpty) {
return "Please enter amount";
}
return null;
},
),
),
SizedBox(height: 3.h),
Container(
height: 6.h,
width: 98.w,
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextField(
readOnly: true,
style: const TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: "Wallet Balance : R " + mf().output.nonSymbol,
border: const OutlineInputBorder(
borderSide:
BorderSide(color: AppColors.primaryBlue),
borderRadius: BorderRadius.horizontal()),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1, color: AppColors.primaryBlue),
),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1, color: AppColors.primaryBlue),
),
),
),
),
SizedBox(height: 3.h),
Container(
height: 50,
width: 400,
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.white)),
child: isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CircularProgressIndicator(
color: AppColors.secondaryColor),
SizedBox(width: 24),
Text(
"Submitting payment...",
style: TextStyle(
color: AppColors.secondaryColor),
)
],
)
: Text(
buttonText,
style: const TextStyle(
fontFamily: Fonts.primaryFont,
fontWeight: FontWeight.bold,
color: AppColors.primaryBlue),
),
onPressed: () {
if (_formKey.currentState!.validate()) {
if (double.parse(txtAmount.text) <= balance!) {
setState(
() {
isLoading = true;
},
);
stokvelTransact.amount =
double.parse(txtAmount.text);
stokvelTransact.memberID = memberID;
stokvelTransact.stokvelID = stokvelID;
stokvelTransact.transactionTypeID = 1;
api
.stokvelDeposit(stokvelTransact,
"StokvelTransaction/StokvelTransact")
.then(
(value) => setState(
() {
Future.delayed(
const Duration(seconds: 3));
isLoading = false;
if (value == "Success") {
ScaffoldMessenger.of(context)
.showSnackBar(snackBar(
content:
'Payment made succesfully',
duration: 5));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(snackBar(
content:
'We have encountered technical problems, Try again later',
duration: 5));
}
},
),
)
.catchError(
(err) {
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
content: err.toString(), duration: 7));
},
);
} else {
ScaffoldMessenger.of(context).showSnackBar(snackBar(
content: "Insuficient funds!", duration: 7));
}
}
},
),
),
],
),
),
),
),
);
}
The above code is for the single page that I want to achieve this
This is what I want to achieve or any suggestions are accepted, I want to mark the Group of Stokvels I want to pay and pay them different accounts I don't know if it's possible please I'm new in flutter it a project I have to get it done as soon as possible this is the source code for my whole payment page, for now, I'm able to pay a single Stokvel Group but I want to select multiple
I highly suggest starting with formatting of the current code - its hard to read and with that hard to maintain.
The simple idea would be:
use List<StokvelDetail> selectedStokvel = []; you created to add the Stokvel's in every time you select Stokvel in SearchBar
Add Map<int,double> amounts = {}; <StokvelId, amount> to keep track of the amount you want to send to each Stokvel
Based on selectedStokvel build multiple 'amount window' widgets
Before submit verify walletBalance >= amounts.values.reduce((a,b)=> a + b)
For each selectedStokvel call api.stokvelDeposit(stokvelTransact, ...
I would primarly focus on spliting this code to multiple Widget classes, there are many schools but I like to have around 150 lines of code in single file at most.
From what i see your file can be easily split into:
Column(
children: [
SizedBox(),
SearchBar(),
SizedBox(),
AmountInput(), --> StokvelAmountInput() for each selectedStokvel
SizedBox(),
WalletBalance(),
SizedBox(),
SubmitButton(),
]),
```

Store textfield value in Map value

so i have this map of questions and have a textfield widget and i'm using a for loop to go through the questions and display them.
id love to store the textfield data in the right place in the map (something like: question 1 => answer 1 and so on)
here's the code:
import 'package:flutter/material.dart';
class CustomQuestionField extends StatefulWidget {
#override
State<CustomQuestionField> createState() => _CustomQuestionFieldState();
}
class _CustomQuestionFieldState extends State<CustomQuestionField> {
final Map<String, String> qna = {
"Everyone should read...": "",
"Two truths and a lie...": "",
"I can quote every line from...": "",
"If I didn't have to work I would...": "",
"People think I am...": "",
"Never have I ever...": "",
"Believe it or not, I...": "",
"I am amazing at...": "",
"My life as a movie...": "",
"My ultimate dinner party guest list...": "",
"The dorkiest thing about me is...": "",
"On the weekend you'll find me...": "",
};
#override
Widget build(
BuildContext context,
) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (var q in qna.keys) question(q),
RaisedButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
color: Colors.purple,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"Submit",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
onPressed: () {
print(qna.values);
}),
],
);
}
Widget question(String question) {
final myController = TextEditingController();
return Padding(
padding: const EdgeInsets.only(top: 15),
child: Stack(
children: [
Card(
elevation: 0,
shape: RoundedRectangleBorder(
side: BorderSide(width: 0.5, color: Colors.black),
borderRadius: BorderRadius.circular(
32,
)),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 15, left: 10),
child: Text(
question,
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
fontWeight: FontWeight.bold),
),
),
TextField(
onChanged: ((value) {
print(value);
}),
onSubmitted: (String ansr) {
setState(() {
});
},
controller: myController,
decoration: InputDecoration(
// filled: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(
color: Color.fromARGB(255, 128, 124, 124),
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(
color: Color.fromARGB(255, 128, 124, 124),
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(
color: Color.fromARGB(255, 128, 124, 124),
),
),
),
),
],
),
),
),
Positioned(
top: -10,
right: -25,
child: RawMaterialButton(
onPressed: () {},
elevation: 2.0,
fillColor: Colors.white,
child: Text(
"X",
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
shape: CircleBorder(),
),
),
],
),
);
}
}
here's a screenshot:
any ideas on how to do it?
just create a map to contain the answers:
final Map<String, String> answers = {};
then in your onSubmitted, add this line:
answers[question] = ansr;
You does not defined key in map, convert your map into this
final Map<String, String> qna = [
{"question" : "Everyone should read...", "answer":""},
{"question" :"Two truths and a lie...", "answer":""},
{"question" :"I can quote every line from...", "answer":""},
.
.
.
{"question" :"On the weekend you'll find me...", "answer":""},
];
**In Text Field setState**
TextField(
onChanged: ((value) {
print(value);
}),
onSubmitted: (String ansr) {
setState(() {
q[answer]=ansr;
});
},
--------------------------------------
RaisedButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
color: Colors.purple,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"Submit",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
onPressed: () {
print(qna["answer"]);
}),

Showing and Hiding Widget give SetState() or markNeedsBuild() called during build error

I have some trouble with hiding and showing widget. So, I have an OTP verification page to verify the code that sent to the user. In that page, when a user click a text button to resend otp code, the button will be hidden and replaced by countdown timer.
showCountdown ?
Center(
child: CountdownTimer(
textStyle: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
endTime: endTime,
onEnd: () {
setState(() {
showCountdown = false;
});
},
),
)
:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Tidak Menerima Kode Verifikasi? ",
style: TextStyle(color: Colors.black54, fontSize: 15),
),
TextButton(
onPressed: () {
// userService.resendOtp(widget.phoneNumber.toString()).then((value) => snackBar(value));
setState(() {
showCountdown = true;
clicked++;
});
},
child: Text(
"Kirim Ulang",
style: TextStyle(
color: Constant.color,
fontWeight: FontWeight.bold,
fontSize: 16),
)
)
],
),
First click is okay, but when clicked for second time, it give this error
The following assertion was thrown building NotificationListener<KeepAliveNotification>:
setState() or markNeedsBuild() called during build.
It shows that the error maybe on this part
onEnd: () {
setState(() {
showCountdown = false;
});
},
Full Code for build method
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/Background.png"),
alignment: Alignment.center,
fit: BoxFit.cover
)
),
child: ListView(
children: <Widget>[
// SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'Verifikasi Nomor HP',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
textAlign: TextAlign.center,
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 30.0, vertical: 8),
child: RichText(
text: TextSpan(
text: "Kode Dikirim Ke Nomor ",
children: [
TextSpan(
text: "${widget.phoneNumber}",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15)),
],
style: TextStyle(color: Colors.black54, fontSize: 15)),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 20,
),
Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
appContext: context,
pastedTextStyle: TextStyle(
color: Constant.color,
fontWeight: FontWeight.bold,
),
length: 6,
obscureText: false,
obscuringCharacter: '*',
blinkWhenObscuring: true,
animationType: AnimationType.fade,
validator: (v) {
if (v!.length < 6) {
return "Harap Masukan Kode OTP Yang Benar";
} else {
return null;
}
},
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(5),
fieldHeight: 50,
fieldWidth: 40,
activeFillColor: Colors.white,
),
cursorColor: Colors.black,
animationDuration: Duration(milliseconds: 300),
errorAnimationController: errorController,
controller: textEditingController,
keyboardType: TextInputType.number,
boxShadows: [
BoxShadow(
offset: Offset(0, 1),
color: Colors.black12,
blurRadius: 10,
)
],
onCompleted: (v) {
print("Completed");
},
onChanged: (value) {
print(value);
setState(() {
currentText = value;
});
},
enablePinAutofill: true,
beforeTextPaste: (text) {
print("Allowing to paste $text");
//if you return true then it will show the paste confirmation dialog. Otherwise if false, then nothing will happen.
//but you can show anything you want here, like your pop up saying wrong paste format or etc
return true;
},
)),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text(
hasError ? "*Please fill up all the cells properly" : "",
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w400),
),
),
SizedBox(
height: 20,
),
showCountdown ?
Center(
child: CountdownTimer(
textStyle: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
endTime: endTime,
onEnd: () {
setState(() {
showCountdown = false;
});
},
),
)
:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Tidak Menerima Kode Verifikasi? ",
style: TextStyle(color: Colors.black54, fontSize: 15),
),
TextButton(
onPressed: () {
// userService.resendOtp(widget.phoneNumber.toString()).then((value) => snackBar(value));
setState(() {
showCountdown = true;
clicked++;
});
},
child: Text(
"Kirim Ulang",
style: TextStyle(
color: Constant.color,
fontWeight: FontWeight.bold,
fontSize: 16),
)
)
],
),
SizedBox(
height: 14,
),
Container(
margin:
const EdgeInsets.symmetric(vertical: 16.0, horizontal: 30),
child: ButtonTheme(
height: 50,
child: TextButton(
onPressed: () {
formKey.currentState!.validate();
// conditions for validating
if (currentText.length != 6 ) {
errorController!.add(ErrorAnimationType.shake); // Triggering error shake animation
setState(() => hasError = true);
} else {
userService.verifyOtp(widget.phoneNumber.toString(), currentText).then((value) {
if(value == "Kode OTP Salah") {
errorController!.add(ErrorAnimationType.shake);
textEditingController.clear();
setState(() {
hasError = true;
snackBar(value);
});
} else {
setState(() {
hasError = false;
snackBar(value);
});
Future.delayed(Duration(seconds: 3)).then( (value) =>
Navigator.of(context).pushReplacement(
new MaterialPageRoute(builder: (context) => new SignIn()))
);
}
});
}
},
child: Center(
child: Text(
"Verifikasi Kode OTP".toUpperCase(),
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
decoration: BoxDecoration(
color: Constant.color,
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
color: Colors.green.shade200,
offset: Offset(1, -2),
blurRadius: 5),
BoxShadow(
color: Colors.green.shade200,
offset: Offset(-1, 2),
blurRadius: 5)
]),
),
],
),
),
),
);
}
I dont have any idea why this is happened, so I need help for this. Thank you.
This error means that the Flutter Engine is instructed to build something (using setState for example), but at the very moment another build is already in progress.
So you have to find out which of your setState statements causes this error, it could be the one at onEnd, you can debug your code to be sure. Than you can add a callback, which will be executed after the current build is completed:
WidgetsBinding.instance.addPostFrameCallback((_){
setState(() {
});
});
If you haven't already done, include this in your main function:
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp()); // or whatever you app class name is
}

Dynamically Change data in a dropdown menu - FLUTTER

I have a horizontal list of Categories; e.g. CARS and below it there is a dropdown menu fetch list of models per every CAR selected in the list. So my issue is after i select eg Toyota and the dropdown menu is filled with models eg - Camry, Vits, Caldina, Hilux, That is fine... but is i select one eg Camry and in the list of CARS i select another CAR eg HONDA.. the UI breaks.. can anyone tell me how i can efficiently reuse the same dropdown and just be changing the arraylist it fetchs from even when one item was selectd
I did something similar like this:
For car brand:
int selectedBrandItem;
int selectedModelItem;
int selectedByYearItem;
var listTemp;
Container(
width: _size.width,
height: _size.height* 0.08,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.greyColor[600]
),
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal:10.0),
child: DropdownButton(
hint: Text(allTranslations.text('brand')),
value: selectedBrandItem,
onChanged: (value){
setState(() {
selectedBrandItem = value;
selectedModelItem = null;
selectedByYearItem = null;
});
},
items: (state.response.brandList == null || state.response.brandList == [])?listTemp:state.response.brandList.map((e) =>
DropdownMenuItem(
value: e.id,
child: Text(
e.brandName,
style: TextStyle(
color: Theme.GreyColor,
fontWeight: FontWeight.w400,
fontSize: 16.0
),
)
)
).toList()??[],
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down, color: Theme.greyColor[500],),
underline: Container(color: Colors.transparent,),
),
),
);
For car model:
Container(
width: _size.width,
height: _size.height* 0.08,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.greyColor[600]
),
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal:10.0),
child: DropdownButton(
hint: Text(allTranslations.text('model')),
value: selectedModelItem,
onChanged: (value){
setState(() {
selectedModelItem = value;
selectedByYearItem = null;
});
},
items: state.response.modelList.map((e) =>
DropdownMenuItem(
value: e.id,
child: Text(
e.modelName,
style: TextStyle(
color: Theme.GreyColor,
fontWeight: FontWeight.w400,
fontSize: 16.0
),
)
)
).toList()??[],
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down, color: Theme.greyColor[500],),
underline: Container(color: Colors.transparent,),
),
),
);
For car year:
Container(
width: _size.width,
height: _size.height* 0.08,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.greyColor[600]
),
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal:10.0),
child: DropdownButton(
hint: Text(allTranslations.text('year')),
value: selectedByYearItem,
onChanged: (value){
setState(() {
selectedByYearItem = value;
});
},
items: (state.response.yearList == null || state.response.yearList == [] )?listTemp:state.response.yearList .map((e) =>
DropdownMenuItem(
value: e.id,
child: Text(
e.year,
style: TextStyle(
color: Theme.GreyColor,
fontWeight: FontWeight.w400,
fontSize: 16.0
),
)
)
).toList()??[],
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down, color: Theme.greyColor[500],),
underline: Container(color: Colors.transparent,),
),
),
);