Related
I'm building a form for shipping and am able to add as many items as possible. (Adding a Widget in a ListView every time a button is pressed)
My question is, once the form widgets are created and filled, how do I get the information from each TextFormField in each Widget?
Once the information is retrieved I will send it to Firebase.
Here's the code I Have:
import 'package:flutter/material.dart';
import 'package:flutter_login_test/helpers/constants.dart';
class AddItemsToRequest extends StatefulWidget {
const AddItemsToRequest({Key? key}) : super(key: key);
#override
State<AddItemsToRequest> createState() => _AddItemsToRequestState();
}
class _AddItemsToRequestState extends State<AddItemsToRequest> {
List<TextEditingController> controllers = [];
List<Widget> fields = [];
RegExp regExp = RegExp('[aA-zZ]');
int quantity = 0;
double weight = 0;
double height = 0;
Widget itemForm() {
return Column(children: [
Container(
decoration:
BoxDecoration(color: grey, border: Border.all(color: black)),
width: double.infinity,
child: const Center(
child: Text('Package details',
style: TextStyle(
fontWeight: FontWeight.bold,
backgroundColor: grey,
fontSize: 24)),
)),
Row(
children: [
Flexible(
child: TextFormField(
onChanged: (value) {
quantity = value as int;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || value is int
? 'Quantity cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Quantity : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
weight = value as double;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || regExp.hasMatch(value)
? 'Weight cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Weight : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
height = value;
},
validator: (value) => value!.isEmpty ? 'Height cannot be empty' : null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Height : "),
),
),
],
),
]);
}
Widget _addTile() {
return ElevatedButton(
child: const Icon(Icons.add),
onPressed: () async {
final controller = TextEditingController();
final field = itemForm();
setState(() {
controllers.add(controller);
fields.add(field);
});
});
}
Widget _listView() {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: fields.length,
itemBuilder: (context, index) {
final item = fields[index];
return Dismissible(
key: ObjectKey(item),
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
fields.removeAt(index);
});
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Package removed')));
},
background: Container(
color: const Color.fromARGB(255, 210, 31, 19),
child: const Center(
child: Text(
'Remove ',
style: TextStyle(
color: white, fontWeight: FontWeight.bold, fontSize: 32),
),
)),
child: Container(
width: double.infinity,
margin: const EdgeInsets.all(5),
child: fields[index],
),
);
},
);
}
Widget _okButton() {
return ElevatedButton(
onPressed: () {
for (var element in fields) {
print(quantity);
}
Navigator.of(context).pop();
print('ok');
},
child: const Text("OK"),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: blue),
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Flexible(child: _addTile()),
SizedBox(
height: MediaQuery.of(context).size.height - 200,
child: _listView()),
Flexible(child: _okButton()),
],
),
);
}
}
I think you are expecting this answer. iterate your list of texteditingcontroller and get the text stored in that controllers one by one.
for (int i = 0; i < controllers.length; i++) {
var data = controllers[i].text;
//print or add data to any other list and insert to another list and save to database
}
I'm stuck on a small point, I'm developing a self-help service application and I take care of creating the form to create an announcement.
For that I thought it a great idea to set it up as a Cupertino Stepper, but when I want the user to choose an image from a list I give, I don't know how to make an image selectable. Here is a picture of what I have so far (left) and what I would like (right):
Comparison between what I have and what I want
And here is the code of the page I have:
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Stepper(
currentStep: currentStep,
onStepTapped: (index) {
setState(() => currentStep = index);
},
onStepContinue: () {
if (currentStep != 3) {
setState (() => currentStep++);
}
},
onStepCancel: () {
if (currentStep != 0) {
setState (() => currentStep--);
}
},
steps: [
Step(
isActive: currentStep >= 0,
title: Text('Choisissez une catégorie'),
content: CupertinoPageScaffold(
child: DefaultTextStyle(
style: TextStyle(
color: CupertinoColors.label.resolveFrom(context),
fontSize: 22.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Catégorie séléctionnée : ', style: TextStyle(fontSize: 14),),
CupertinoButton(
padding: EdgeInsets.zero,
// Display a CupertinoPicker with list of fruits.
onPressed: () => _showDialog(
CupertinoPicker(
magnification: 1.22,
squeeze: 1.2,
useMagnifier: true,
itemExtent: _kItemExtent,
onSelectedItemChanged: (int selectedItem) {
setState(() {
_selectedCategorie = selectedItem;
});
},
children:
List<Widget>.generate(_CategorieNames.length, (int index) {
return Center(
child: Text(
_CategorieNames[index],
),
);
}),
),
),
// This displays the selected fruit name.
child: Text(
_CategorieNames[_selectedCategorie],
),
),
],
),
),
)
),
Step(
isActive: currentStep >= 1,
title: Text("Choisir le titre de l'annonce"),
content: Padding(
padding: EdgeInsets.only(top: 20),
child: TextField(
maxLength: 20,
decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(30)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 1.5),
borderRadius: BorderRadius.circular(30)
),
labelText: "Titre de l'annonce"
),
),
)
),
Step(
isActive: currentStep >= 2,
title: Text('Ajouter une description'),
content: Padding(
padding: EdgeInsets.only(top: 20),
child: TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
maxLength: 250,
decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(30)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 1.5),
borderRadius: BorderRadius.circular(30)
),
labelText: "Description de l'annonce"
),
),
)
),
Step(
isActive: currentStep >= 3,
title: Text('Ajouter une image'),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child:
Image.asset("images/Jardinage.png"),
),
Expanded(
child:
Image.asset("images/baby sitting.png"),
),
Expanded(
child:
Image.asset("images/Coiffure.png"),
),
],
),
),
],
)
],
),
),
);
I thank you in advance for your help !
You can make the image selectable by adding GestureDetector and changing the _selectedImageIndex using setState on each tap.
Step(
isActive: currentStep >= 3,
title: const Text('Ajouter une image'),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
_selectedImage = 0;
});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: _selectedImage == 0
? Colors.green
: Colors.transparent)),
child: Image.asset(
"assets/images/provinces/1.png"))),
),
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
_selectedImage = 1;
});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: _selectedImage == 1
? Colors.green
: Colors.transparent)),
child: Image.asset(
"assets/images/provinces/2.png"))),
),
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
_selectedImage = 2;
});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: _selectedImage == 2
? Colors.green
: Colors.transparent)),
child: Image.asset(
"assets/images/provinces/3.png"))),
),
],
),
),
Alternate Solution : You can refactor the image selector widget as well
The variables will be
var _selectedImageIndex = 0;
final _images = [
"assets/images/provinces/1.png",
"assets/images/provinces/2.png",
"assets/images/provinces/3.png",
];
SelectabImage widget will be
class SelectableImage extends StatelessWidget {
const SelectableImage({
Key? key,
required this.isSelected,
required this.imageAsset,
required this.onTap,
}) : super(key: key);
final bool isSelected;
final String imageAsset;
final void Function(String imageAsset) onTap;
#override
Widget build(BuildContext context) {
return Expanded(
child: GestureDetector(
onTap: () => onTap(imageAsset),
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: isSelected ? Colors.green : Colors.transparent)),
child: Image.asset(imageAsset),
),
),
);
}
}
Step function will be reduced to
Step(
isActive: currentStep >= 3,
title: const Text('Ajouter une image'),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int i = 0; i < _images.length; i++)
SelectableImage(
isSelected: _selectedImageIndex == i,
onTap: (selectedImageIndex) {
setState(() {
_selectedImageIndex = i;
});
},
imageAsset: _images[i],
),
],
),
),
I am using flutter_typeahead: ^3.2.4
and now i dont know how to add a drop down search history
When i have not searched for anything search box returns search history and when the search is done, add it to search history
This is my typeahead code now i want to add a search history box after clicked on suggestion:
class _TypeAheadSearchBarState extends State<TypeAheadSearchBar> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _typeAheadController = TextEditingController();
String _selectedDrug;
#override
Widget build(BuildContext context) {
return Form(
key: this._formKey,
child: Padding(
padding: EdgeInsets.only(
top: Dimensions.height20,
right: Dimensions.height30,
left: Dimensions.height30,
bottom: Dimensions.height20,
),
child: Column(
children: [
TypeAheadFormField(
textFieldConfiguration: TextFieldConfiguration(
autocorrect: true,
controller: this._typeAheadController,
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: () {
print(_typeAheadController.text);
},
icon: Icon(
CupertinoIcons.search,
color: Palette.mainBlueTheme,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(Dimensions.radius20),
),
borderSide: BorderSide(color: Palette.mainBlueTheme),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(Dimensions.radius20),
),
borderSide:
BorderSide(width: 3, color: Palette.mainBlueTheme),
),
labelText: 'Hôm nay bạn muốn tìm thuốc gì?'),
),
suggestionsCallback: (String pattern) {
return typeAhead.getTypeAhead(pattern);
},
itemBuilder: (context, Map<String, dynamic> suggestion) {
return ListTile(
title: AppTextTitle(
text: suggestion['tenThuoc'],
color: Colors.black54,
size: Dimensions.font18,
fontWeight: FontWeight.normal),
);
},
transitionBuilder: (context, suggestionsBox, controller) {
return suggestionsBox;
},
onSuggestionSelected: (Map<String, dynamic> suggestion) {
this._typeAheadController.text = suggestion['tenThuoc'];
},
validator: (value) {
if (value.isEmpty) {
return 'Hãy chọn nhập và chọn một tên thuốc bất kì';
}
},
onSaved: (value) => this._selectedDrug = value,
),
],
),
),
);
}
I am pretty new to flutter
hope to get a tutorial on this or any suggested way
This my contacts list page
class Contacts extends StatefulWidget with NavigationStates {
#override
_ContactsState createState() => _ContactsState();
}
class _ContactsState extends State<Contacts>{
DatabaseHelper databaseHelper = DatabaseHelper();
List<contacts> contactsList;
int count = 0;
#override
Widget build(BuildContext context, ) {
if(contactsList == 0){
contactsList = List<contacts>();
updateListView();
}
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text("Contacts"),
backgroundColor: Colors.lightGreenAccent,
centerTitle: true,
),
body: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(4.0),
margin: EdgeInsets.all(5.0),
child: TextField(
//controller: searchController,
decoration: InputDecoration(
labelText:'Search Contacts',
border: new OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: new BorderSide(
color: Colors.pinkAccent
)
),
prefixIcon: Icon(
Icons.search,
color: Colors.black,
)
),
),
),
Expanded(
child: ListView.builder(
itemCount: count,
itemBuilder: (context , int position){
return Card(
elevation: 1.0,
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.pinkAccent,width: 1),
borderRadius: BorderRadius.circular(20)
),
child: Container(
margin: EdgeInsets.all(6.0),
padding: EdgeInsets.all(4.0),
color: Colors.white,
child: ListTile(
leading: CircleAvatar(
radius: 30.0,
backgroundColor: Colors.lightBlueAccent,
child: Icon(Icons.person,color: Colors.black,),
),
title: Text(this.contactsList[position].first_name,style: TextStyle(color: Colors.black,fontSize: 28.0),),
subtitle: Text(this.contactsList[position].last_name,style:TextStyle(color: Colors.black38,fontSize: 15.0),),
trailing: GestureDetector(
child: Icon(Icons.delete, color: Colors.pinkAccent,),
onTap: () {
_delete(context, contactsList[position]);
},
),
),
),
);
},
),
)
],
),
floatingActionButton: new FloatingActionButton(onPressed: null,
child: new Icon(Icons.dialpad,color: Colors.black,size: 30,),
backgroundColor: Colors.pinkAccent,
),
bottomNavigationBar: CurvedNavigationBar(
color: Colors.lightGreenAccent,
backgroundColor: Colors.white,
buttonBackgroundColor: Colors.pinkAccent,
height: 50,
index: 1,
items:<Widget>[
Icon(Icons.call,size: 25,color: Colors.black,),
Icon(Icons.home,size: 30,color: Colors.black,),
Icon(Icons.person_add_rounded,size: 25,color: Colors.black,),
],
animationDuration: Duration(
milliseconds: 400
),
animationCurve: Curves.easeIn,
onTap: (index) async {
if (index == 0)
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return logs();
}
)
);
if (index == 1)
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return Contacts();
}
)
);
if (index == 2)
navigateToDetail(contacts('',''));
}
),
);
}
updateListView() {
final Future<Database> dbFuture = databaseHelper.initalizeDatabase();
dbFuture.then((database) {
Future<List<contacts>> contactsListFuture = databaseHelper.getContactList();
contactsListFuture.then((contactsList){
setState(() {
this.contactsList = contactsList;
this.count = contactsList.length;
});
});
});
}
Color getStorageColor() {
int storage;
switch (storage) {
case 1:
return Colors.pinkAccent;
break;
case 2:
return Colors.lightBlueAccent;
break;
default:
return Colors.lightBlueAccent;
}
}
void navigateToDetail(contacts contact) async{
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return AddContacts(contact);
}));
if (result == true) {
updateListView();
}
}
void _delete(BuildContext context, contacts contact) async {
int result = await databaseHelper.deleteContact(contact.id);
if (result != 0) {
_SnackBar(context, 'Contact Deleted Successfully');
updateListView();
}
}
void _SnackBar(BuildContext context, String message) {
final snackBar = SnackBar(
content: Text(message),
action: SnackBarAction(
label: 'Undo',
onPressed: (){},
),
);
// ignore: deprecated_member_use
Scaffold.of(context).showSnackBar(snackBar);
}
}
This is my contacts details page
import 'dart:io';
//import 'package:contacts_service/contacts_service.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
//import 'package:sqflite/sqflite.dart';
import 'package:mycontacts_app/models/Contact.dart';
import 'dart:async';
import 'package:mycontacts_app/utils/database_helper.dart';
//import 'package:intl/intl.dart';
class AddContacts extends StatefulWidget {
final contacts contact;
AddContacts(this.contact);
//AddContacts(contacts contact);
#override
State<StatefulWidget> createState() {
// _AddContactsState();
return _AddContactsState(this.contact);
}
}
class _AddContactsState extends State<AddContacts> {
//TextEditingController _fnameController,_numberController,_lnameController;
DatabaseHelper helper = DatabaseHelper();
PickedFile _imageFile;
final ImagePicker _picker = ImagePicker();
_AddContactsState(this.contact);
TextEditingController _fnameController = TextEditingController();
TextEditingController _numberController = TextEditingController();
TextEditingController _lnameController = TextEditingController();
contacts contact;
List _Storage = ['Phone','Sim'];
//String _storageval;
#override
Widget build(BuildContext context) {
//_nameController = contacts.first_name
_fnameController.text = contact.first_name;
_lnameController.text = contact.last_name;
_numberController.text = contact.phone_no as String;
return Scaffold(
appBar: AppBar(
title: Text("New Contact"),
backgroundColor: Colors.lightGreenAccent,
centerTitle: true,
),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(
vertical: 40.0,
horizontal: 10.0,
),
//margin: EdgeInsets.all(15),
child: Form(
child: Column(
//crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
padding: EdgeInsets.only(left: 16.0,right: 16.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.white
),
borderRadius: BorderRadius.circular(20.0),
),
child: DropdownButton(
hint: Text('Store In '),
dropdownColor: Colors.black12,
elevation: 5,
icon: Icon(Icons.arrow_drop_down),
iconSize: 20.0,
isExpanded: true,
style: TextStyle(
color: Colors.black,fontSize: 18.0
),
items: _Storage.map((value){
return DropdownMenuItem(
value: value,
child: Text(value),
);
}).toList(),
value: getStorageAsString(contact.storage),
onChanged: (value){
setState(() {
//_storageval = value;
updateStorageAsInt(value);
});
},
),
),
),
imageProfile(),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _fnameController,
onChanged: (value){
updateFirstname();
},
decoration: InputDecoration(
hintText: 'First Name',
prefixIcon: Icon(Icons.person),
//prefixText: "Name",
suffixIcon: Icon(Icons.keyboard_arrow_down),
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
contentPadding: EdgeInsets.all(15),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _lnameController,
onChanged: (value){
updateLastName();
},
decoration: InputDecoration(
hintText: 'Last Name',
prefixIcon: Icon(Icons.person),
//prefixText: "Name",
//suffixIcon: Icon(Icons.keyboard_arrow_down),
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
contentPadding: EdgeInsets.all(15),
),
),
),
// SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _numberController,
onChanged: (value){
//updateNumber();
},
decoration: InputDecoration(
hintText: 'Number',
prefixIcon: Icon(Icons.phone_android),
//prefixText: "Name",
//suffixIcon: Icon(Icons.keyboard_arrow_down),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
),
),
),
//SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
//controller: _nameController,
decoration: InputDecoration(
hintText: 'Address',
prefixIcon: Icon(Icons.location_on_rounded),
//prefixText: "Name",
suffixIcon: Icon(Icons.keyboard_arrow_down),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
),
),
),
//SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
//controller: _nameController,
decoration: InputDecoration(
hintText: 'Email',
prefixIcon: Icon(Icons.email),
//prefixText: "Name",
//suffixIcon: Icon(Icons.keyboard_arrow_down),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
),
),
),
//SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
//controller: _nameController,
decoration: InputDecoration(
hintText: 'Website',
prefixIcon: Icon(Icons.language),
//prefixText: "Name",
//suffixIcon: Icon(Icons.keyboard_arrow_down),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
),
),
),
//SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
//controller: _nameController,
decoration: InputDecoration(
hintText: 'Work Info',
prefixIcon: Icon(Icons.business),
//prefixText: "Name",
//suffixIcon: Icon(Icons.keyboard_arrow_down),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
),
),
),
/*ListView.builder(
itemBuilder: (context, index){
return ExpansionTile(
title: ListTile(
title: TextField(
decoration: InputDecoration(
hintText: "Name"
),
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
),
),
children: <Widget>[
ListTile(
title:TextFormField(
decoration: InputDecoration(
hintText: "Name Prefix"
),
)
),
ListTile(
title:TextFormField(
decoration: InputDecoration(
hintText: " First Name"
),
)
),
ListTile(
title:TextFormField(
decoration: InputDecoration(
hintText: " Middle Name"
),
)
),
ListTile(
title:TextFormField(
decoration: InputDecoration(
hintText: "Last Name"
),
)
),
ListTile(
title:TextFormField(
decoration: InputDecoration(
hintText: "Name Suffix"
),
)
)
],
);
}
)*/
Padding(
padding: const EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
color: Colors.lightGreenAccent,
textColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.pinkAccent),
),
onPressed: () {
debugPrint("Save button clicked");
_save();
},
child: Text(
"Save"
),
),
),
Container(width: 5.0,),
Expanded(
child: RaisedButton(
color: Colors.lightGreenAccent,
textColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.pinkAccent),
),
onPressed: () {
_delete();
},
child: Text(
"Cancel"
),
),
)
],
),
)
],
),
),
),
),
);
}
Widget imageProfile() {
return Center(
child: Stack(
children: <Widget>[
CircleAvatar(
radius: 50.0,
backgroundImage: _imageFile==null? AssetImage("assets/default.png"):FileImage(File(_imageFile.path)),
),
Positioned(
bottom: 20.0,
right: 20.0,
child: InkWell(
onTap: () {
showModalBottomSheet(
context: context,
builder: ((builder) => bottomSheet()),
);
},
child: Icon(
Icons.camera_alt,
color: Colors.lightGreenAccent,
size: 28.0,
),
),
),
],
),
);
}
Widget bottomSheet() {
return Container(
height: 100.0,
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
),
child: Column(
children: <Widget>[
Text(
"Choose Contact Image",
style: TextStyle(
fontSize: 20,
),
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton.icon(
icon: Icon(Icons.camera),
onPressed: (){
takePhoto(ImageSource.camera);
},
label: Text("Camera"),
),
FlatButton.icon(
icon: Icon(Icons.image),
onPressed: (){
takePhoto(ImageSource.gallery);
},
label: Text("Gallery"),
)
],
)
],
),
);
}
void takePhoto(ImageSource source) async {
final pickedFile = await _picker.getImage(
source: source,
);
setState(() {
_imageFile = pickedFile;
});
}
void updateFirstname(){
contact.first_name = _fnameController.text;
}
// Update the description of Note object
void updateLastName() {
contact.last_name = _lnameController.text;
}
/*void updateNumber() {
contact.phone_no = _numberController.text as int;
}*/
void _save() async {
moveToLastScreen();
//n.date = DateFormat.yMMMd().format(DateTime.now());
int result;
if (contact.id != null) { // Case 1: Update operation
result = await helper.updateContact(contact);
} else { // Case 2: Insert Operation
result = await helper.insertContact(contact);
}
if (result != 0) { // Success
_showAlertDialog('Status', 'Contact Saved Successfully');
} else { // Failure
_showAlertDialog('Status', 'Problem Saving Contact');
}
}
void moveToLastScreen() {
//Navigator.pop(context);
Navigator.pop(context, true);
}
void _delete() async {
moveToLastScreen();
// Case 1: If user is trying to delete the NEW NOTE i.e. he has come to
// the detail page by pressing the FAB of NoteList page.
if (contact.id == null) {
_showAlertDialog('Status','No Contact was deleted');
return;
}
// Case 2: User is trying to delete the old note that already has a valid ID.
int result = await helper.deleteContact(contact.id);
if (result != 0) {
_showAlertDialog('Status','Contact Deleted Successfully');
} else {
_showAlertDialog('Status', 'Error Occured while Deleting Contact');
}
}
void _showAlertDialog(String title, String message) {
AlertDialog alertDialog = AlertDialog(
title: Text(title),
content: Text(message),
);
showDialog(
context: context,
builder: (_) => alertDialog
);
}
void updateStorageAsInt(String value) {
switch (value) {
case 'Phone':
contact.storage = 1;
break;
case 'Sim':
contact.storage = 2;
break;
}
}
// Convert int priority to String priority and display it to user in DropDown
String getStorageAsString(int value) {
String storage;
switch (value) {
case 1:
storage = _Storage[0]; // 'High'
break;
case 2:
storage = _Storage[1]; // 'Low'
break;
}
return storage;
}
}
The contact card and icon is displayed but the name is not displaying.
I was even getting error like :-
This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
It is not even showing the position or file of error
And I am not being able to solve the error .
I have a bloc which I use to upload images from the gallery. I then have a TextField where I enter text. And finally another bloc where I have a button. The button is used to submit the data to a server(image and text). My problem is enabling the button. My code for enabling is:
class ObservationPage extends StatefulWidget {
#override
_ObservationPageState createState() => _ObservationPageState();
}
class _ObservationPageState extends State<ObservationPage> {
List<File> files = [];
TextEditingController _descriptionController = TextEditingController();
TextEditingController _taskNameController = TextEditingController();
String taskName;
List<String> _selectedUsers = [];
bool _enabled = false;
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
BlocProvider.of<ImageBloc>(context).add(DeleteAllImages(files: files));
return true;
},
child: Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
centerTitle: true,
iconTheme: IconThemeData(
color: RioColours.darkGrey,
),
backgroundColor: Colors.grey[200],
elevation: 0,
title: Text('Observation',style:TextStyle(color: Colors.black))
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(left: 20.0, right: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20,),
Column(children: [
AutoSizeText(
'Make an Observation and assign to a colleague ',
maxLines: 1,
style: RioTextStyle.auditQuestion(context),
),
SizedBox(height: 20,),
AttachPhoto(),
SizedBox(height: 20,),
BlocBuilder<ImageBloc, ImageState>(builder: (context, state) {
if (state is ImageInitial) {
return Container();
}
if (state is ImageLoadInProgress) {
return CircularProgressIndicator();
}
if (state is ImageLoadSuccess) {
//print(state.files);
files = state.files;
return SizedBox(
//height: MediaQuery.of(context).size.height*.5,
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: state.files.length,
itemBuilder: (context, item) {
return Padding(
padding: const EdgeInsets.only(bottom:10.0),
child: ImageContainer(context: context, file: state.files[item]),
);
}),
);
}
if (state is NoImages) {
return Container();
}
if (state is ImageLoadFailure) {
return Container();
}
return Container();
})
]),
Text(
'Notes',
style: RioTextStyle.auditHeaders(context),
),
SizedBox(
height:10
),
SizedBox(height: 140,
child: TextField(
textInputAction: TextInputAction.next,
keyboardType: TextInputType.multiline,
maxLines: 5,
controller: _descriptionController,
onChanged: (String value) {
setState(() {});
},
style: TextStyle(fontSize: 16.0, height: 2.0, color: Colors.black),
decoration: new InputDecoration(
hintStyle: RioTextStyle.hintText(context),
fillColor: Colors.white,
filled: true,
focusedBorder: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey[300]),
),
hintText: "Enter your notes here"
),
),
),
SizedBox(
height: MediaQuery.of(context).size.height * .04,
),
Text(
'Task Name',
style: RioTextStyle.auditHeaders(context),
),
SizedBox(
height: 10
),
TextField(
controller: _taskNameController,
onChanged: (String value) {
setState(() {});
},
textInputAction: TextInputAction.next,
style: TextStyle(fontSize: 16.0, height: 2.0, color: Colors.black),
decoration: new InputDecoration(
fillColor: Colors.white,
filled: true,
focusedBorder: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey[300]),
),
hintStyle: RioTextStyle.hintText(context),
hintText: "Enter your task name here"
),
),
SizedBox(
height: 20
),
SizedBox(
height: 20
),
BlocBuilder<ObservationBloc, ObservationState>(builder: (context, state) {
if (state is UsersLoadInProgress) {
return Center(child: CircularProgressIndicator());
}
if (state is UsersLoadSuccess) {
final users = state.users;
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
'Assign to',
style: RioTextStyle.auditHeaders(context),
),
SizedBox(
height: MediaQuery.of(context).size.height * .02,
),
MultiSelectDialogField(
buttonIcon: Icon(Icons.arrow_drop_down,color: Colors.grey,),
chipDisplay: MultiSelectChipDisplay(
chipColor: Colors.white,
textStyle: TextStyle(color: Colors.black),
),
onConfirm: (results) {
_selectedUsers.clear();
for (User user in results) {
_selectedUsers.add(user.id);
setState(() {
_enabled = true;
});
}
// _selectedUsers = results;
print(_selectedUsers);
},
items: users.map((user) => MultiSelectItem<User>(user, user.first_name)).toList(),
title: Text(
'Assign Owners',
style: TextStyle(color: RioColours.splashBlue),
),
cancelText: Text(
"CANCEL",
style: TextStyle(color: RioColours.splashBlue),
),
confirmText: Text(
"ASSIGN",
style: TextStyle(color: RioColours.splashBlue),
),
buttonText: Text(
"Choose Owners",
style: RioTextStyle.dropDownHint(context),
),
),
SizedBox(
height: MediaQuery.of(context).size.height * .05,
),
]);
}
if (state is UserLoadFailure) {
return Text('error');
}
return Container();
}),
BlocConsumer<ButtonBloc, ButtonState>(listener: (context, state) {
if (state is UploadFailure) {
RioHelpers.showFailureFlushBar(context, 'Error Uploading');
Navigator.of(context).pop();
}
if (state is UpLoadSuccess) {
_submit();
}
}, builder: (context, state) {
if (state is Loading) {
return Center(child: CircularProgressIndicator());
}
if (state is ButtonInitial) {
print(_enabled);
return SizedBox(
height: MediaQuery.of(context).size.height * .07,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: (_descriptionController.text.isNotEmpty && _taskNameController.text.isNotEmpty && _enabled) ? () => callupLoad() : null,
color: RioColours.splashBlue,
child: Text(
'Submit',
style: RioTextStyle.buttonText(context),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
);
}
if (state is UpLoadSuccess) {
BlocProvider.of<ImageBloc>(context).add(DeleteAllImages(files: files));
return SizedBox(
height: MediaQuery.of(context).size.height * .07,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: (_descriptionController.text.isNotEmpty && _taskNameController.text.isNotEmpty && _enabled) ? () => callupLoad() : null,
color: RioColours.splashBlue,
child: Text(
'Submit',
style: RioTextStyle.buttonText(context),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
);
}
if (state is UploadFailure) {
return SizedBox(
height: MediaQuery.of(context).size.height * .07,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () {},
//onPressed: (controller.text.isNotEmpty && _enabled) ? () => callupLoad() : null,
color: RioColours.splashBlue,
child: Text(
'Submit',
style: RioTextStyle.buttonText(context),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
);
}
return Container(
color: Colors.yellow,
height: 10,
);
}),
SizedBox(
height: MediaQuery.of(context).size.height * .12,
),
],
),
),
)),
);
}
callupLoad() {
BlocProvider.of<ButtonBloc>(context).add(UploadTaskRequest(files: files, notes: _descriptionController.text, taskName: _taskNameController.text, owners: _selectedUsers));
}
_submit() async {
print('called called called called called ');
RioHelpers.showSuccessFlushBar(context, 'Observation recorded');
BlocProvider.of<ImageBloc>(context).add(DeleteAllImages(files: files));
await Future.delayed(Duration(seconds: 3));
Navigator.of(context).pop();
}
#override
void initState() {
BlocProvider.of<ObservationBloc>(context).add(RequestUsers());
super.initState();
print("init calledx");
_enabled = false;
}
}
So the _controller works great for enabling/disabling the button. However _enabled which is a boolean state variable is my problem. In my blocbuilder I update my state to _enabled= true when the image upload is successful. However this is not making any difference to enabling the button. I've also updated the state variable using a bloclistener but that didn't work either.
How can I trigger the button to be enabled when I upload an image from the Gallery
Set a local variable in the builder, not in the class itself, unless you want to use in another place. If you want to do so, wrap the variable assignment in a setState call.