Store textfield value in Map value - flutter

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"]);
}),

Related

Field has not been initialized

tags in my code is a List which is comes from previous page,
I want to be able to remove and add items to it in my current page,
first I tried to initialize it in my initState but when I want to remove tags it doesn't work.
I guessed it is about the initialization, so I removed it from initState but now I am getting this error message Field 'tags' has not been initialized. I will attach my full code and I appreciate any suggestions about it. Thanks.
PS: I tried initializing tags with tags=[] in my initState but I can't remove any of the tags. It has a GestureDetector to remove tags, when I press it nothing happens. I guess initializing in the build function causes it, but I don't know where to initialize it that I could be able to edit it while the list is coming from another screen.
also when I added tags = widget.tags.where((e) => e != null && e != "").toList(); to my initiState and I inspect tags value, there is an empty string in addtion to other values at the end of the list.
import 'dart:convert';
import 'dart:developer';
import 'package:double_back_to_close/toast.dart';
import 'package:flutter/material.dart';
import 'package:pet_store/main.dart';
import 'package:pet_store/widgets/tag_preview.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'dart:async';
import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:pet_store/widgets/tag_retrieve_preview.dart';
import 'utils/utils.dart';
class update_pet extends StatefulWidget {
var id;
var name;
var status;
var category;
var tags ;
update_pet(
{this.id, this.name, this.status, this.category, this.tags, Key? key})
: super(key: key);
#override
_update_petState createState() => _update_petState();
}
class _update_petState extends State<update_pet> {
final _picker = ImagePicker();
Future<void> _openImagePicker() async {
final XFile? pickedImage =
await _picker.pickImage(source: ImageSource.gallery);
if (pickedImage != null) {
setState(() {
final bytes = File(pickedImage.path).readAsBytesSync();
base64Image = "data:image/png;base64," + base64Encode(bytes);
});
}
}
String? base64Image;
TextEditingController nameController = TextEditingController();
TextEditingController categoryController = TextEditingController();
TextEditingController tagController = TextEditingController();
late File imageFile;
late List<dynamic> tags;
bool isLoading = false;
void initState() {
super.initState();
nameController.text = widget.name;
categoryController.text = widget.category;
addTag();
}
void addTag() {
setState(() {
tags.add(tagController.text);
tagController.clear();
});
}
String? dropdownvalue;
var items = [
'available',
'pending',
'sold',
];
#override
Widget build(BuildContext context) {
tags = widget.tags.where((e) => e != null && e != "").toList();
// inspect(tags);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.indigo,
title: const Text('Update a pet'),
leading: GestureDetector(
child: Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
onTap: () {
// Navigator.pop(context);
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
PetStoreHomePage(LoggedIn: true),
),
(route) => false,
);
},
),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Card(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
children: [
const ListTile(
// leading,
title: Text(
"General Information",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
TextField(
controller: nameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: "Enter your pet's name",
),
),
DropdownButton(
hint: const Text('Select Status'),
value: dropdownvalue,
icon: const Icon(Icons.keyboard_arrow_down),
items: items.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(items),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
),
],
),
),
elevation: 8,
shadowColor: Colors.grey.shade300,
margin: const EdgeInsets.all(20),
shape: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white)),
),
Card(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
children: [
const ListTile(
// leading,
title: Text(
"Category",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
TextField(
controller: categoryController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: "Specify your pet's category",
),
),
],
),
),
elevation: 8,
shadowColor: Colors.grey.shade300,
margin:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
shape: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white)),
),
Card(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
// leading,
title: Text(
"Tags",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Flexible(
fit: FlexFit.loose,
child: ListView.builder(
shrinkWrap: true,
itemCount: tags.length,
itemBuilder: (_, index) {
print(tags);
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5.0, vertical: 3.0),
child: GestureDetector(
child: tagRetrievePreview(tags[index]),
onTap: () {
print("REMOVED "+tags[index]);
tags.removeAt(index);
}),
);
},
),
),
TextField(
controller: tagController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Specify your pet's tags",
suffixIcon: IconButton(
icon: const Icon(
Icons.add_circle_outline_sharp,
color: Color.fromARGB(255, 129, 128, 128),
size: 30,
),
onPressed: () {
addTag();
print(tags);
},
),
),
),
],
),
),
elevation: 8,
shadowColor: Colors.grey.shade300,
margin:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
shape: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white)),
),
Card(
child: Column(
children: [
const ListTile(
title: Text(
"Images",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
(base64Image != null)
? SizedBox(
width: 100,
height: 100,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
image: DecorationImage(
image: image(base64Image!).image,
fit: BoxFit.fill),
)),
)
: SizedBox(
width: 100,
height: 100,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.grey.shade300,
),
child: Icon(
Icons.camera_alt,
color: Colors.grey.shade800,
size: 30,
),
),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 100),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 129, 128, 128)),
padding: MaterialStateProperty.all(
const EdgeInsets.symmetric(horizontal: 20)),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: const BorderSide(
color: Color.fromARGB(255, 129, 128, 128),
width: 2.0,
),
),
),
),
child: const Text(
'Select Image',
style:
TextStyle(fontSize: 15.0, color: Colors.white),
),
onPressed: _openImagePicker),
),
],
),
elevation: 8,
shadowColor: Colors.grey.shade300,
margin:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
shape: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white)),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 120),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.indigo),
padding: MaterialStateProperty.all(
const EdgeInsets.symmetric(horizontal: 40)),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: const BorderSide(
color: Colors.indigo,
width: 2.0,
),
),
),
),
child: isLoading
? const SizedBox(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Colors.white)),
height: 15.0,
width: 15.0,
)
: const Text(
'Update Pet',
style:
TextStyle(fontSize: 17.0, color: Colors.white),
),
onPressed: () async {
if (nameController.text.isEmpty) {
nameController.text = widget.name;
}
if (tagController.text.isEmpty) {
tagController.text = widget.tags;
}
if (categoryController.text.isEmpty) {
categoryController.text = widget.category;
}
if (dropdownvalue == null) {
dropdownvalue = widget.status;
}
print('Pressed');
Map data = {
"id": random.nextInt(10000),
///random it integer
"name": nameController.text,
"category": {
"id": set_category_id(categoryController.text),
"name": categoryController.text,
},
"photoUrls": [base64Image],
"tags": set_tags(tags),
"status": dropdownvalue
};
var body = json.encode(data);
var response = await http.put(
Uri.parse(
"https://api.training.testifi.io/api/v3/pet"),
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: body);
print(response.body);
print(response.statusCode);
if (response.statusCode == 201 ||
response.statusCode == 200) {
print('success');
Toast.show("Pet is successfully updated.", context);
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
PetStoreHomePage(LoggedIn: true),
),
(route) => false,
);
} else {
Toast.show(
"ERROR! Updating pet failed. Please try again.",
context);
}
}),
),
],
),
),
),
);
}
}
tags = widget.tags.where((e) => e != null && e != "").toList();
This line in build method will constantly take value from widget.tags and create a list of items thats not null and empty.
Please add this in initState.
Just initialize it
List<dynamic> tags = [];
PS: I tried initializing tags with tags=[] in my initState but I can't
remove any of the tags.
You need to add setState to rebuild the page.

setState not updating the value in the screen using Flutter desktop

So I'm trying to update the value of the drop down list using the setState, but when I select a value from the list, the value on the screen won't be able to change
import 'package:demo_app_admin/Custom/custom_Font.dart';
import 'package:flutter/material.dart';
import '/Custom/Custom_Raised_Bottun.dart';
import '/Custom/Header.dart';
import '/Custom/inputField.dart';
class LoginView extends StatefulWidget {
#override
_LoginViewState createState() => _LoginViewState();
}
class _LoginViewState extends State<LoginView> {
#override
Widget build(BuildContext context) {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
String _dropdownvalue = "Global admin";
List<String> _items = <String> ["Global admin", "Institution admin"];
return Scaffold(
body: Container(
width: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(begin: Alignment.topCenter, colors: [
Colors.teal[700]!,
Colors.teal[200]!,
Colors.teal[400]!
]),
),
child: Column(
children: <Widget>[
const SizedBox(
height: 80,
),
if (!isKeyboard)
Header(
padding: const EdgeInsets.all(20),
crossAxisAlignment: CrossAxisAlignment.start,
head: "Welcome",
headTextStyle:
const TextStyle(color: Colors.white, fontSize: 40),
sizedBoxHeight: 10,
subtitle: "Sign In to Your Admin Account",
subtitleTextStyle:
const TextStyle(color: Colors.white, fontSize: 18),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(60),
topRight: Radius.circular(60),
)),
child: Padding(
padding: const EdgeInsets.all(30),
child: SingleChildScrollView(
reverse: true,
padding: EdgeInsets.all(32),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
const SizedBox(
height: 40,
),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10)),
child: Column(
children: <Widget>[
InputField(
labelText: 'Email',
padding: EdgeInsets.all(10),
borderSide: BorderSide(color: Colors.grey),
hintText: "Enter your email",
color: Colors.grey,
inputBorder: InputBorder.none,
obscureText: false,
enableSuggestion: true,
autoCorrect: true,
onSaved: (value) {},
// (value){controller.email = value!;},
validator: (value) {
if (value == null) {
print("ERROR");
}
},
),
InputField(
labelText: 'Password',
padding: EdgeInsets.all(10),
borderSide: BorderSide(color: Colors.grey),
hintText: "Enter your password",
color: Colors.grey,
inputBorder: InputBorder.none,
obscureText: true,
enableSuggestion: false,
autoCorrect: false,
onSaved: (value) {},
// (value){ controller.password = value!;},
validator: (value) {
if (value == null) {
print("ERROR");
}
},
),
],
),
),
const SizedBox(
height: 40,
),
here is the issue
DropdownButton<String>(
value: _dropdownvalue,
icon: Icon(Icons.keyboard_arrow_down),
items: _items.map((String _items) {
return DropdownMenuItem<String>(
value: _items,
child: CustomFont(text: _items),
);
}).toList(),
onChanged: (value) {
setState(() => _dropdownvalue = value!);
}),
const SizedBox(
height: 40,
),
CustomRaisedButton(
width: 200,
height: 50.0,
margin: const EdgeInsets.symmetric(horizontal: 50),
color: Colors.teal.shade500,
borderRadius: BorderRadius.circular(10),
text: "LOGIN",
textColor: Colors.white,
fontSize: 17,
fontWeight: FontWeight.bold,
function: () {}
// {
// _formKey.currentState?.save();
// if(_formKey.currentState?.validate() !=null){
// controller.signInWithEmailAndPassword();
// }
// },
),
SizedBox(
height: 10,
),
],
),
),
),
),
))
],
),
),
);
}
}
The issue is here, you are declaring variables inside build. Therefore, variables get reset to default value on every build. Means setState.
Declare variables outside the build method.
class _LoginViewState extends State<LoginView> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String _dropdownvalue = "Global admin";
List<String> _items = <String>["Global admin", "Institution admin"];
#override
Widget build(BuildContext context) {
final isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
return Scaffold(
More about StatefulWidget.

I want to implement OTP verification screen without any package

I want to implement OTP verification screen without any package.
when i entered the number it should move to next input field
I m using this code in my current project take a refrence this will help
class Otp extends StatefulWidget {
final String? phnNumber;
final String ? code;
String? from;
Otp({Key ?key, this.phnNumber, this.from, this.code}) : super(key:
key);
#override
_OtpState createState() => _OtpState();
}
class _OtpState extends State<Otp> {
double ? height ;
double ? width;
TextEditingController ? contrller1;
TextEditingController ? contrller2;
TextEditingController ? contrller3;
TextEditingController ? contrller4;
SendOtpRequest resend = SendOtpRequest();
SharedPreferences ? prefs;
getSharedPreferences () async
{
prefs = await SharedPreferences.getInstance();
}
String Code = "";
#override
void initState() {
// TODO: implement initState
super.initState();
contrller1 = TextEditingController();
contrller2 = TextEditingController();
contrller3 = TextEditingController();
contrller4 = TextEditingController();
getSharedPreferences();
}
#override
Widget build(BuildContext context) {
height= MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.height;
final verifyprovider = Provider.of<PostDataProvider>(context);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
toolbarHeight:height! * 0.07802345,
titleSpacing: 0,
backgroundColor: HexColor("#18263d"),
automaticallyImplyLeading: false,
leading: Padding(
padding: const EdgeInsets.only(left: 8.0,),
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Container(
color: Colors.transparent,
child: Image.asset("assets/images/back_ic-1.png")),
),
),
// SizedBox(width: width!*0.001234,),
title:Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: height!/15,
width: height!/15,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: 2,
color:HexColor("#fc4f00"),
)),
child: Padding(
padding: const EdgeInsets.all(1.0),
child: Container(
height: height!/11,
width: height!/11,
decoration: BoxDecoration(
image: const DecorationImage(
image:
AssetImage("assets/images/home_logo.png"),
fit: BoxFit.fill
),
shape: BoxShape.circle,
border: Border.all(
width: 1,
color:HexColor("#fc4f00"),
)),
),
),
),
SizedBox(width: width! * 0.04234,),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text("Verification",
style: GoogleFonts.oswald(fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: width! * 0.03345
),),
),
],
) ,
),
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 24, horizontal: 32),
child: Column(
children: [
Text("We have send verification code on your mobile number",
style: GoogleFonts.oswald(fontStyle: FontStyle.normal,
fontSize: width!*0.0234,
color: HexColor("#8b8b8b")),
),
SizedBox(height: height!/38,),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_textFieldOTP(first: true, last: false,controllerr:
contrller1),
_textFieldOTP(first: false, last: false,controllerr:
contrller2),
_textFieldOTP(first: false, last: false,controllerr:
contrller3),
_textFieldOTP(first: false, last: true, controllerr:
contrller4),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap:() {
resend.phoneNumber= widget.phnNumber;
resend.countryCode = widget.code;
verifyprovider.resendOtp(context,
jsonEncode(resend));
},
child: Text("Resend OTP?",
style: GoogleFonts.oswald(fontStyle:
FontStyle.normal,
fontSize: width!*0.0234,
color: HexColor("#fc4f00")),
),
),
),
SizedBox(height: height!/28,),
GestureDetector(
onTap: (){
if(contrller1!.text.isNotEmpty&&
contrller2!.text.isNotEmpty&&contrller3!.
text.isNotEmpty&&contrller4!.text.isNotEmpty){
verifyOtpRequest verify = verifyOtpRequest();
verify.phoneNumber = widget.phnNumber;
verify.otp=
contrller1!.text+contrller2!.
text+contrller3!.text+contrller4!.text;
verifyprovider.otpVerification(context,
jsonEncode(verify), widget.from);
}else{
CommonUtils.showToast(msg: "Please fill all the
fields ");
}
},
child: Container(
height: height!/18,
width: width,
decoration: BoxDecoration(
color: HexColor("#fc4f00"),
borderRadius: BorderRadius.circular(10)
),
child: Center(
child: Text("Verify",style: TextStyle(
color: Colors.white,
fontSize: width!*0.02345
),),
)
),
),
],
),
],
),
),
),
);
}
Widget _textFieldOTP({bool ? first, last,
TextEditingController ?
controllerr}) {
return Container(
height:height!/12 ,
child: AspectRatio(
aspectRatio: 1.0,
child: TextField(
controller: controllerr,
autofocus: true,
onChanged: (value) {
if (value.length == 1 && last == false) {
FocusScope.of(context).nextFocus();
}
if (value.length == 0 && first == false) {
FocusScope.of(context).previousFocus();
}
},
showCursor: false,
readOnly: false,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
keyboardType: TextInputType.number,
maxLength: 1,
decoration: InputDecoration(
counter: Offstage(),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 2, color: Colors.black54),
borderRadius: BorderRadius.circular(12)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(width: 2, color: Colors.black54),
borderRadius: BorderRadius.circular(12)),
),
),
),
);
}
}
When the length of the input data reaches one, you will have to change the text field focus node.
For Example
If you are in the first field, and you enter a number field one focus should be lost, and field two should be in focus. This can be done, by requestFocus.
This article will of help for you: Flutter Focus

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(),
]),
```

ValueNotifier<String>#97fe7(go to the gym)

Hi everyone : the problem is simple but i just cant find the solution
here is my code :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todoye_app_angela/models/task_data.dart';
class AddTaskScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
ValueNotifier<String> newTaskTitle = ValueNotifier("");
return Container(
color: Color(0xFF757575),
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.limeAccent[400],
borderRadius: BorderRadius.only(
topLeft: Radius.circular(60),
topRight: Radius.circular(60),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Add Task',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.brown[900]),
),
SizedBox(
height: 12,
),
TextField(
onChanged: (newText) {
newTaskTitle.value = newText;
},
autocorrect: false,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.brown[800]!,
width: 2,
),
borderRadius: BorderRadius.circular(30),
),
hintText: 'Type Your Task ...',
labelStyle: TextStyle(
color: Colors.green[900],
),
helperStyle: TextStyle(
color: Colors.brown[900],
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(60),
borderSide: BorderSide(
color: Colors.brown[900]!,
width: 2,
),
),
),
),
SizedBox(
height: 12,
),
ValueListenableBuilder<String>(
valueListenable: newTaskTitle,
builder: (context, taskt, child) {
return ElevatedButton(
onPressed: taskt.isEmpty
? null
: () {
Provider.of<TaskData>(context, listen: false)
.addTask(newTaskTitle.toString());
print(taskt);
Navigator.pop(context);
// Provider.of<TaskData>(context, listen: false)
// .addTask(newTaskTitle);
// Navigator.pop(context);
},
child: Text(
'Add',
style: TextStyle(color: Colors.brown[900]),
),
style: ButtonStyle(
backgroundColor: MaterialStateColor.resolveWith(
(states) => Colors.lightGreen),
elevation: MaterialStateProperty.resolveWith((states) => 6),
shadowColor: MaterialStateColor.resolveWith(
(states) => Colors.green),
minimumSize: MaterialStateProperty.resolveWith(
(states) => Size.square(40.67)),
),
);
},
),
],
),
),
);
}
}
im trying to add some tasks in my todo app . simply the user have to type something in the textfield and this value is passed to the addtask function in my taskdata class to notify the listeners about it . the problem was th newTaskTitle variable is of type ValueNotifier and the value of my input function is a String i tried to solve this problem by adding the toString method here:
Provider.of<TaskData>(context, listen: false)
.addTask(newTaskTitle.toString());
but it returns this : ValueNotifier#97fe7(go to the gym) on the screen .. i just want the pure String from user .
please help me solve this problem ...
I appreciate it inadvance.
Your are using ValueNotifier.
Use ValueNotifier.value , newTaskTitle.value in your case to get the String value.
code:
...
...
Provider.of<TaskData>(context, listen: false)
.addTask(newTaskTitle.value);
...