I made a form to add an image and its information in a ListView.builder(), this is the image screenshot and code:
class _AddNewProductState extends State<AddNewProduct> {
String? dropdownValue = 'Fruits';
String? productName;
int? productPrice;
Future<void> openMobileImagePicker() async {
final XFile? pickedMobileImage =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedMobileImage != null) {
setState(() {
ImageFiles.mobileImage = File(pickedMobileImage.path);
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(15),
child: SingleChildScrollView(
child: Center(
child: Column(
children: [
const Text(
'Add New Product To The Market',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
Padding(
padding: const EdgeInsets.all(15),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: const [
BoxShadow(
offset: Offset(0, 10),
blurRadius: 30,
)
],
),
child: Padding(
padding: const EdgeInsets.all(25),
child: Form(
key: UniversalKey.formKey,
child: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
openMobileImagePicker();
});
},
child: const Text('Add Product Image'),
),
const SizedBox(
height: 20,
),
Container(
height: 120,
width: 120,
decoration: const BoxDecoration(
boxShadow: [
BoxShadow(
blurRadius: 15,
color: Colors.grey,
)
],
shape: BoxShape.circle,
),
child: CircleAvatar(
backgroundImage: (ImageFiles.mobileImage !=
null)
? Image.file(ImageFiles.mobileImage!,
fit: BoxFit.fill)
.image
: null),
),
const SizedBox(
height: 20,
),
TextFormField(
onSaved: (value) {
setState(() {
ProductDetails.productName = value!;
});
},
decoration: const InputDecoration(
labelText: 'Product Name',
hintText: 'Add Product Name'),
),
const SizedBox(
height: 20,
),
TextFormField(
onSaved: (value) {
setState(() {
ProductDetails.productPrice = value!;
});
},
decoration: const InputDecoration(
labelText: 'Product Price',
hintText: 'Add Product Price'),
),
const SizedBox(
height: 20,
),
DropdownButton<String>(
value: dropdownValue,
items: productCategory,
onChanged: (item) =>
setState(() => dropdownValue = item),
),
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
listOfProducts.add(
{
'productImage' : ProductDetails.productImage,
'productName' : ProductDetails.productName,
'productPrice' : ProductDetails.productPrice,
'productCategory' : dropdownValue,
}
);
}
,
child: const Text('Add Product!'))
,
const SizedBox(
height: 20,
),
ElevatedButton(onPressed: () {
setState(() {
Navigator.push(context, MaterialPageRoute(builder: (context) => const GroceryPage(),),);
});
}, child: const Text('Go To Hompage'),),
],
),
),
),
),
)
],
),
),
),
),
),
);
}
}
When I tap ‘Submit’ it’s supposed to add the information in a ListView.builder() , this is the image screenshot and code:
class ProductsListView extends StatelessWidget {
const ProductsListView({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: fruitsList.length,
itemBuilder: (BuildContext context, int index) {
return ClipRect(
child: Container(
width: 140.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
color: Colors.white,
boxShadow: const [
BoxShadow(
blurRadius: 10,
color: Colors.black,
),
],
),
margin: const EdgeInsets.all(10.0),
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 10, 10),
child: Column(
children: [
Image.file(
listOfProducts[index]['productImage']
,
height: 80.0,
width: 90.0,
),
const SizedBox(
height: 15,
),
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
listOfProducts[index]['productName'],
style: const TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
Text(
listOfProducts[index]['productCategory'],
textAlign: TextAlign.left,
style: const TextStyle(
height: 1.5,
color: kDarkGrey,
fontSize: 12.5,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
Row(
children: [
Text(
listOfProducts[index]['productPrice'],
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
const Spacer(),
const AddProduct(),
],
)
],
),
),
),
);
},
);
}
}
But the result is:
How can I fix it? I tried many ways with no success, I don’t know which part of the code causes the error?
Relative code snippets:
class ImageFiles {
static File? mobileImage;
static Uint8List? webImage;
}
class ProductDetails {
static File? productImage;
static String? productName;
static String? productPrice;
}
List<Map<String, dynamic>> listOfProducts = [
];
I hope someone can help me via checking the project repo:
https://github.com/ahmloutfy/Grocery-Store.git
2
Answers
Since there is no
stackTrace
provided, I’ll suggest using a debugger or print statements to check the value ofmobileImage
. See where it’s getting null. You can track it with the errorstackTrace
in the console.A possible reason for the error could be the following.
You’re using a static property of the
ImageFiles
class to store the image selected by the user. This property might be getting overridden.A better approach would be to create an instance of the class
ImageFiles
, initialize it_AddNewProductState
and pass it to theProductsListView
widget.Switching from static properties.
In
_AddNewProductState
, initialize theImageFile
and use that object.For example:
Now pass this
ImageFile
to any other widget likeGroceryPage
or add this in thelistOfProducts
as needed.1- Add a variable productImage in _AddNewProductState
2- in this method openMobileImagePicker replace this line:
with this:
3- replace this:
with this:
4- replace this:
with this:
5- replace this:
with this:
6- replace this:
with this: