Streambuilder error in SingleChildScrollView flutter - flutter

This is the streambuilder wrapped under SingleChildScrollView inside the body of scaffold. Scroll View is not working after streambuilder is placed under SingleChildScrollView. StreamBuilder fetches data from firebase through cloud firestore.
body: Container(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance
.collection(
'blogsDatabase/${widget.blogUIDInFirebase}/comments')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
final _commentsFetched = snapshot.data.documents;
List<CommentBubble> _commentBubbleWidget = [];
for (var comment in _commentsFetched) {
_commentBubbleWidget.add(
CommentBubble(
name: comment.data['name'],
comment: comment.data['comment'],
),
);
}
return Expanded(
child: ListView(
children: _commentBubbleWidget
),
);
},
),
),
Container(
margin: EdgeInsets.all(10),
child: Material(
shadowColor: Colors.orange,
child: TextField(
onChanged: (value) {
readerAddComment = value;
},
keyboardType: TextInputType.emailAddress,
decoration:
kRegDetailFieldDeco.copyWith(hintText: 'Add comment'),
),
),
),
FlatButton(
onPressed: () {
if (_nameReader != null &&
widget.readerEmail != null &&
readerAddComment != null) {
Firestore.instance
.collection(
'blogsDatabase/${widget.blogUIDInFirebase}/comments')
.document()
.setData(
{
'name': _nameReader,
'email': widget.readerEmail,
'comment': readerAddComment,
},
);
}
},
child: Text('Add comment')),
],
),
),
),
Comment Bubble Class, it is a stateless widget which will display the comments.
class CommentBubble extends StatelessWidget {
final String name;
final String comment;
CommentBubble({this.name, this.comment});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Text('$name --- $comment'),
);
}
}
Error shown in console
RenderBox was not laid out: RenderRepaintBoundary#dd879 relayoutBoundary=up1 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1694 pos 12: 'hasSize'

It is Happening Because your Widget Structure due to which error is there is like
-Container
-SingleChildScrollView
-Expanded
-Column
-Expanded
-Expanded
-ListView
Now See This Error Which you are getting , it is saying that it is error regarding the size , Wrap your Column in Some other widget rather than Expanded

It seems that you need space to place your ListView inside the Column().
Remove the Expanded widget, and replace it with Container.
For example:
Container(
height: 100,
child: ListView(
children: _commentBubbleWidget
),)
But, I don't recommend the solution above for you. That's too bad for the UI (just my opinion). Because, you use ListView inside Column. By using this way, you have to decide height of the ListView. Don't forget, the phones' size are vary.
Better to separate the ListView, and place your textfield in BottomNavigationBar.
This is mine:
Scaffold(
appBar: AppBar(
title: textCustom(
'Review ${widget.destination}', Colors.black87, 20, 'Hind'),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
),
onPressed: () {
Navigator.pop(context);
}),
iconTheme: IconThemeData(color: Colors.black87, size: 10),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: StreamBuilder<QuerySnapshot>(
stream: kategori
.document(widget.kategori)
.collection(widget.subKategori)
.document(widget.docId)
.collection("review")
.orderBy("timeStamp", descending: true)
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) return new Text('${snapshot.error}');
if (snapshot.data == null)
return Center(
child: textCustom(
'Loading...', Colors.black87, 14, 'Montserrat'));
final review= snapshot.data.documents;
return snapshot.data.documents.isNotEmpty
? ListView.builder(
itemCount: review.length,
itemBuilder: (context, index) {
return Comment(
name: review[index]['name'],
profilePhoto: review[index]['foto'],
comments: review[index]['review'],
date: (review[index]['timeStamp'] != null)
? DateFormat.yMMMd().format(DateTime.parse(
review[index]['timeStamp']
.toDate()
.toString(),
))
: '',
);
})
: Center(child: Text('Empty'));
}),
),
bottomNavigationBar: Padding(
padding: MediaQuery.of(context).viewInsets,
child: BottomAppBar(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: textMessageController,
onChanged: (text) {
input = text;
setState(() {
enableButton = text.isNotEmpty;
});
},
textCapitalization: TextCapitalization.sentences,
maxLines: null,
style: TextStyle(
color: Colors.black87,
fontSize: 16,
fontFamily: 'Montserrat'),
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: new BorderSide(color: Colors.white),
borderRadius: new BorderRadius.circular(8.0),
),
focusedBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.white),
borderRadius: new BorderRadius.circular(8.0),
),
contentPadding:
EdgeInsets.only(left: 16.0, bottom: 16.0, top: 16.0),
hintText: 'Write some review',
),
)),
SizedBox(
width: 8.0,
),
enableButton
? IconButton(
onPressed: handleSendMessage,
icon: Icon(
Icons.send,
color: Color(0xFFDB5C48),
))
: IconButton(
onPressed: () {},
icon: Icon(
Icons.send,
color: Colors.grey,
))
],
),
),
),
),
);

Related

Dynamic listview in flutter

I'm new to Flutter, but I'm trying to make an app with a ListView. The ListView is a list of exercises, within each exercise the number of sets can be added. The problem comes when i press the button add exercise. The above exercise with sets is just copied. I would like a new exercise tab with 0 sets. Below the code can be found.
Here is a picture of the list.
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "null",
);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
titleSection,
// ignore: unnecessary_new
new TextField(
controller: eCtrl,
onSubmitted: (text) {
litems.add(text);
eCtrl.clear();
setState(() {});
},
),
Expanded(
// ignore: unnecessary_new
child: new ListView.builder(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Card(
child: Padding(
padding: EdgeInsets.all(10),
child: ExpansionTile(
initiallyExpanded: true,
title: Text(
litems[Index],
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(child: Text(" ")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
],
),
// ignore: sort_child_properties_last
children: <Widget>[
ListView.builder(
shrinkWrap: true,
itemCount: sets.length,
itemBuilder:
(BuildContext context, int Index1) {
return Dismissible(
key: UniqueKey(),
// only allows the user swipe from right to left
direction:
DismissDirection.endToStart,
// Remove this product from the list
// In production enviroment, you may want to send some request to delete it on server side
onDismissed: (_) {
setState(() {
sets.removeAt(Index1);
});
},
// ignore: sort_child_properties_last
child: Card(
elevation: 0,
child: Padding(
padding: EdgeInsets.all(1),
child: ListTile(
title: Text(
" ",
style: const TextStyle(
fontSize: 10,
fontWeight:
FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(
child: Text(" "),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
],
),
))),
background: Container(
color: Colors.red,
margin:
const EdgeInsets.symmetric(
horizontal: 15,
),
alignment: Alignment.centerRight,
child: const Text(
"Delete",
style: TextStyle(
color: Colors.white,
),
)));
}),
Padding(
padding: EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () {
sets.add('sets-test');
setState(() {});
},
child: const Text('+ Add Set')),
),
const SizedBox(height: 5),
],
leading: IconButton(
icon: const Icon(
Icons.close,
color: Colors.red,
),
onPressed: () {
litems.removeAt(Index);
setState(() {});
},
),
)));
})),
ElevatedButton(
onPressed: () {
litems.add("new");
setState(() {});
},
child: const Text('Add Exercises')),
ElevatedButton(
onPressed: () {
createUser(user1, "5");
exercise.setExerciseTotals();
//saveExercise(exercise);
final workout = Workout([exercise, exercise1], "Det gik fint",
"10", 60, "type", "name", true, 0, 0, 0);
//workout.setWorkoutTotals();
saveWorkout(workout, userID);
},
child: const Text('pop')),
bottomSection,
],
),
));
}
You are not copy the item, you logic is that add new Item with null value, change decoratedField to this:
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "0",
);

Why does futurebuilder keep fetching data everytime TextFormField is pressed?

I have a statelsess widget built like this where a futurebuilder fetches data and then returns a StatefullTextFormFieldWidget:
Statless Widget{
build:
Futurebuilder(snapshot, context){
future: GetDocumentFromFirebase(id);
if(snapshot.hasData){
return StatefullTextFormFieldWidget(snapshot);
}
}
}
The StatefullTextFormfieldWidget contains a appbar and scaffold with with 2 TextFormFields and workes as it should (when it was offline).
The bug occurs when any of my forms gets onFocusScope in the StatefullTextFormFieldWidget. Then the future starts to refetch data from firebase. It does NOT trigger the rebuild function so my app actually works fine since the state remains, but the main problem is that the app unnecessarily starts fetching data from firestore everytime the user clicks on a TextFormField. I only want to fetch data once when the user enter the screen and then stick with that snapshot as long as the user remains on the screen.
I really cant understand how the futurebuilder can continue fetch data without being rebuilt.
FuturebuilderWidget:
import 'package:flutter/material.dart';
import 'package:MyApp/manage_orders/handle/widgets/form_has_handling.dart';
import 'package:MyApp/services/firestore.dart';
import 'package:MyApp/services/models.dart';
class HandleOrderScreen extends StatefulWidget {
static const routeName = '/handle-order-screen';
#override
State<HandleOrderScreen> createState() => _HandleOrderScreenState();
}
class _HandleOrderScreenState extends State<HandleOrderScreen> {
#override
Widget build(BuildContext context) {
final String id = ModalRoute.of(context)!.settings.arguments as String;
return FutureBuilder<Map>(
future: FirestoreService().getOrderPriceUserBoat(id),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
appBar: AppBar(
title: Text(''),
),
body: Center(
child: Center(child: CircularProgressIndicator()),
),
);
} else if (snapshot.hasError) {
return Scaffold(
appBar: AppBar(
title: Text('Error'),
),
body: Center(
child: Text(snapshot.error.toString()),
),
);
} else if (snapshot.hasData) {
var snapshotData = snapshot.data;
Order order = snapshotData!['order'];
return TextFormFieldWidget(order: order);
} else {
return Scaffold(
appBar: AppBar(
title: Text('Error'),
),
body: Center(
child: Text('Something went wrong'),
),
);
}
});
}
}
TextFormFieldWidget:
import 'package:flutter/material.dart';
import 'package:MyApp/services/models.dart';
class TextFormFieldWidgetextends StatefulWidget {
const TextFormFieldWidget({
Key? key,
required this.order,
}) : super(key: key);
final Order order;
#override
State<FormHasHandlingWidget> createState() => _TextFormFieldWidgetState();
}
class _TextFormFieldWidgetState extends State<TextFormFieldWidget> {
final commentController = TextEditingController();
final priceController = TextEditingController();
static final formkey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text('Handle'),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
padding: EdgeInsets.all(5),
height: size.height - 120,
child: Form(
key: formkey,
child: Column(
children: [
Container(
padding: EdgeInsets.all(2),
width: double.infinity,
height: 120,
child: Card(
color: Color.fromARGB(255, 241, 235, 235),
child: Container(
child: RichText(
text: TextSpan(
style:
TextStyle(color: Colors.black, fontSize: 20),
children: <TextSpan>[
TextSpan(
text: 'Test Name\n',
),
TextSpan(
text: 'Order.nr:',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(
text: '${widget.order.orderNumber} \n',
),
TextSpan(
text: 'Car: ',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(
text: widget.order.carModel + '\n',
),
],
),
),
),
),
),
Container(
padding: EdgeInsets.all(2),
child: Align(
alignment: Alignment.topLeft,
child: Text(
" Type:",
style: TextStyle(color: Colors.grey),
),
),
),
SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.black, width: 2),
),
child: Container(
padding: EdgeInsets.all(5),
child: TextFormField(
controller: priceController,
decoration: InputDecoration(labelText: 'Price: '),
validator: (value) {
if (value != null) {
if (value.length < 1) {
return 'Wright the price';
} else {
return null;
}
}
},
keyboardType: TextInputType.number,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.black, width: 2),
),
child: Container(
padding: EdgeInsets.all(5),
child: TextFormField(
controller: commentController,
decoration:
InputDecoration(labelText: 'Description:'),
keyboardType: TextInputType.multiline,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
minLines: 2,
maxLines: 5,
validator: (value) {
if (value != null) {
if (value.length < 10) {
return 'Give a short description';
} else {
return null;
}
}
},
),
),
),
Container(
padding: EdgeInsets.all(5),
child: ElevatedButton(
child: Text('Send in'),
onPressed: () {},
style: ElevatedButton.styleFrom(
fixedSize: Size(size.width, 50),
primary: Color.fromARGB(255, 223, 208, 0)),
),
),
Spacer(),
Container(
padding: EdgeInsets.all(5),
child: ElevatedButton(
child: Text('Finish order'),
onPressed: () {},
style: ElevatedButton.styleFrom(
fixedSize: Size(size.width, 50),
primary: Color.fromARGB(255, 255, 17, 0)),
),
),
],
),
),
),
SizedBox(
height: 200,
),
],
),
),
);
}
}
My guess is that your GetDocumentFromFirebase function does a new get() call to Firestore each time it runs, which happens every time the widget is rendered.
If you want to prevent refetching the document every time, put the code in a stateful widget, and keep the Future<DocumentSnapshot> in a state variable that you only initialize once.
Also see Randal's excellent explanation on Fixing a common FutureBuilder and StreamBuilder problem

Flutter || Checkbox on hover doesn't give on tap cursor permission

I am working on dropdownmenu items where in the drop-down menu item there are several checkboxes but any of the checkboxes on hover don't give on tap cursor permission.
This is a very strange thing I found out as I have already used the checkbox before but this type of error I didn't receive.
I think maybe the problem is in dropdownmenu.
I have also included the video for better understanding of my problem.
my code :-
Container(
width: 160,
//margin: const EdgeInsets.only(top: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), color: Colors.white),
child: ListTileTheme(
contentPadding: EdgeInsets.all(0),
dense: true,
horizontalTitleGap: 0.0,
minLeadingWidth: 0,
child: ExpansionTile(
iconColor: primaryBackgroundLightGrey,
title: Text(
listOFSelectedItem.isEmpty
? "Project type"
: listOFSelectedItem[0],
style: t5O40),
children: <Widget>[
Container(
height: 10,
color: primaryBackgroundLightGrey,
),
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.listOFStrings.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: [
Container(
height: 10,
),
Container(
margin: const EdgeInsets.only(bottom: 8.0),
child: _ViewItem(
item: widget.listOFStrings[index],
selected: (val) {
selectedText = val;
if (listOFSelectedItem.contains(val)) {
listOFSelectedItem.remove(val);
} else {
listOFSelectedItem.add(val);
}
widget.selectedList(listOFSelectedItem);
setState(() {});
},
itemSelected: listOFSelectedItem
.contains(widget.listOFStrings[index])),
),
],
);
},
),
],
),
),
),
class _ViewItem extends StatelessWidget {
String item;
bool itemSelected;
final Function(String) selected;
_ViewItem(
{required this.item, required this.itemSelected, required this.selected});
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Padding(
padding: EdgeInsets.only(
left: size.width * .015,
),
child: Row(
children: [
SizedBox(
height: 2,
width: 2,
child: Checkbox(
value: itemSelected,
onChanged: (val) {
selected(item);
},
hoverColor: Colors.transparent,
checkColor: Colors.white,
activeColor: Colors.grey),
),
SizedBox(
width: size.width * .010,
),
Text(item, style: t3O60),
],
),
);
}
}
You can adapt the example to your own code
dropdownBuilder: _customDropDownExample,
popupItemBuilder: _customPopupItemBuilderExample,
Widget _customDropDownExample(
BuildContext context, UserModel? item, String itemDesignation) {
if (item == null) {
return Container();
}
return Container(
child: (item.avatar == null)
? ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(),
title: Text("No item selected"),
)
: ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
title: Text(item.name),
subtitle: Text(
item.createdAt.toString(),
),
),
);
After that
Widget _customPopupItemBuilderExample(
BuildContext context, UserModel item, bool isSelected) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 8),
decoration: !isSelected
? null
: BoxDecoration(
border: Border.all(color: Theme.of(context).primaryColor),
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: ListTile(
selected: isSelected,
title: Text(item.name),
subtitle: Text(item.createdAt.toString()),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
),
);
I am using this package https://pub.dev/packages/dropdown_button2
Multiselect Dropdown with Checkboxes
final List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Align(
alignment: AlignmentDirectional.center,
child: Text(
'Select Items',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
),
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
//disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final _isSelected = selectedItems.contains(item);
return InkWell(
onTap: () {
_isSelected
? selectedItems.remove(item)
: selectedItems.add(item);
//This rebuilds the StatefulWidget to update the button's text
setState(() {});
//This rebuilds the dropdownMenu Widget to update the check mark
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
],
),
),
);
},
),
);
}).toList(),
//Use last selected item as the current value so if we've limited menu height, it scroll to last item.
value: selectedItems.isEmpty ? null : selectedItems.last,
onChanged: (value) {},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
itemPadding: EdgeInsets.zero,
selectedItemBuilder: (context) {
return items.map(
(item) {
return Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
selectedItems.join(', '),
style: const TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
);
},
).toList();
},
),
),
),
);
}

Adding filter button to different screens

I have a working filter button in search page of my app
I need to add it as floating button in other pages such as category, view all products etc
Here is the working filter button code for searchscreen.
class SearchProductWidget extends StatelessWidget {
final bool isViewScrollable;
final List<Product> products;
SearchProductWidget({this.isViewScrollable, this.products});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(Dimensions.PADDING_SIZE_SMALL),
child: Column(
children: [
Row(
children: [
Expanded(
child: Text(
'Search result for \"${Provider.of<SearchProvider>(context).searchText}\" (${products.length} items)',
style: titilliumRegular.copyWith(
fontSize: Dimensions.FONT_SIZE_DEFAULT),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
InkWell(
onTap: () => showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (c) => SearchFilterBottomSheet()),
child: Container(
padding: EdgeInsets.symmetric(
vertical: Dimensions.PADDING_SIZE_EXTRA_SMALL,
horizontal: Dimensions.PADDING_SIZE_SMALL),
decoration: BoxDecoration(
color: ColorResources.getLowGreen(context),
borderRadius: BorderRadius.circular(5),
border: Border.all(
width: 1, color: Theme.of(context).hintColor),
),
child: Row(children: [
///Image.asset(Images.filter_image, width: 10, height: 10, color: ColorResources.getPrimary(context)),
SizedBox(width: Dimensions.PADDING_SIZE_EXTRA_SMALL),
Text('Filter'),
]),
),
),
],
),
SizedBox(height: Dimensions.PADDING_SIZE_SMALL),
Expanded(
child: StaggeredGridView.countBuilder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(0),
crossAxisCount: 2,
itemCount: products.length,
//shrinkWrap: true,
staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
itemBuilder: (BuildContext context, int index) {
return ProductWidget(productModel: products[index]);
},
),
),
],
),
);
}
}
I'm trying to create a floating action button to work as a filter in different screens
Here is one of the screen which I need the filter button working-
class AllProductScreen extends StatelessWidget {
final ScrollController _scrollController = ScrollController();
final ProductType productType;
AllProductScreen({#required this.productType});
// Future<void> _loadData(BuildContext context, bool reload) async {
// String _languageCode = Provider.of<LocalizationProvider>(context, listen: false).locale.countryCode;
// await Provider.of<BrandProvider>(context, listen: false).getBrandList(reload, context);
// await Provider.of<ProductProvider>(context, listen: false).getLatestProductList('1', context, _languageCode, reload: reload);
//
//
//
// }
#override
Widget build(BuildContext context) {
// _loadData(context, false);
return Scaffold(
backgroundColor: ColorResources.getHomeBg(context),
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Provider.of<ThemeProvider>(context).darkTheme
? Colors.black
: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(5),
bottomLeft: Radius.circular(5))),
leading: IconButton(
icon:
Icon(Icons.arrow_back_ios, size: 20, color: ColorResources.WHITE),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
productType == ProductType.FEATURED_PRODUCT
? 'Featured Product'
: 'Latest Product',
style: titilliumRegular.copyWith(
fontSize: 20, color: ColorResources.WHITE)),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (c) => SearchFilterBottomSheet()),
icon: const Icon(Icons.filter_list),
label: const Text('Filter'),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: SafeArea(
child: RefreshIndicator(
backgroundColor: Theme.of(context).primaryColor,
onRefresh: () async {
// await _loadData(context, true);
return true;
},
child: CustomScrollView(
controller: _scrollController,
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(Dimensions.PADDING_SIZE_SMALL),
child: ProductView(
isHomePage: false,
productType: productType,
scrollController: _scrollController),
),
),
],
),
),
),
);
}
}
The exception I'm getting is
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by gesture ═══════════════════════════════════════════
The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator

inavlid argument(s) /Exception caught by widgets library

I have an empty card widget which I used it for opening adding page, my problem is when I pushed from main categories screen I can add main category, but When I used this empty card button on sub category screen of any main category, add screen is opening but when I pushed add I took invalid argument(s) error app is broken. How can ı solve this issue?.
class EmptyCard extends StatelessWidget {
EmptyCard({this.where});
final String where;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top:15.0),
child: TextButton(
onPressed: (){
if(where=="homeScreen"){
showModalBottomSheet(
context: context,
builder: (BuildContext context)=> AddMenuScreen(buttonText: "Menü Ekle",route:where),
);
}
else if(where=="subCategoryScreen"){
showModalBottomSheet(
context: context,
builder: (BuildContext context)=> AddMenuScreen(buttonText: "Tarif Ekle",route:where),
);
}
},
child: Container(
height: 180,
width: 180,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.black12.withOpacity(0.1),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.add_circle_outline_outlined,size: 100,color: Colors.grey.shade400,),
],
),
),
),
);
}
}
class AddMenuScreen extends StatefulWidget {
AddMenuScreen({this.categoryId,this.buttonText, this.route});
final int categoryId;
final String route;
final String buttonText;
static String id="addMenuScreen";
#override
_AddMenuScreenState createState() => _AddMenuScreenState();
}
class _AddMenuScreenState extends State<AddMenuScreen> {
final stickerList= List<String>.generate(23, (index) => "images/sticker$index");
int selectedIndex=-1;
Color _containerForStickersInactiveColor=Colors.white;
Color _containerForStickersActiveColor=Colors.black12;
String chosenImagePath;
String newCategoryName;
int addScreenImageNum;
#override
Widget build(BuildContext context) {
return Material(
child: Container(
color: kColorTheme9,
child: Container(
height: 400,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topRight: Radius.circular(40),topLeft: Radius.circular(40)),
),
child:Padding(
padding:EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: kColorTheme2,
borderRadius: BorderRadius.circular(90)
),
child: TextField(
style: TextStyle(
color: Colors.black,
fontFamily:"Graduate",
fontSize: 20,
),
textAlign: TextAlign.center,
onChanged: (value){
newCategoryName=value;
},
decoration: InputDecoration(
border:OutlineInputBorder(
borderRadius: BorderRadius.circular(90),
borderSide: BorderSide(
color: Colors.teal,
),
),
hintText: "Menü ismi belirleyin",
hintStyle: TextStyle(
color: Colors.black.withOpacity(0.2),
fontFamily: "Graduate",
),
),
),
),
SizedBox(height: 20,),
Text(" Yana kadırarak menünüz icin bir resim secin",textAlign: TextAlign.center,
style: TextStyle(fontFamily: "Graduate", fontSize: 12),),
SizedBox(height: 20,),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: stickerList.length,
itemBuilder: (context,index){
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: index == selectedIndex ?
_containerForStickersActiveColor :
_containerForStickersInactiveColor,
),
child:TextButton(
child: Image(
image: AssetImage("images/sticker$index.png"),
),
onPressed: (){
setState(() {
selectedIndex = index;
});
},
),
);
}
),
),
SizedBox(height: 20,),
Container(
decoration: BoxDecoration(
border: Border.all(style: BorderStyle.solid),
color: kColorTheme7,
borderRadius: BorderRadius.circular(90),
),
child: TextButton(
onPressed: (){
if(widget.route=="homeScreen"){
Navigator.pop(context, ModalRoute.withName(HomeScreen.id));
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>HomeScreen(newCategoryName: newCategoryName,
newCategoryImagePath: "images/sticker$selectedIndex.png")));
}
else if(widget.route=="subCategoryScreen"){
Navigator.pop(context, ModalRoute.withName(SubCategoriesScreen.id));
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>SubCategoriesScreen(categoryId: widget.categoryId,subCategoryName: newCategoryName,
subCategoryImagePath:"images/sticker$selectedIndex.png" )));
}
},
child: Text(widget.buttonText, style: TextStyle(fontSize: 20, color: Colors.white,
fontFamily: "Graduate", fontWeight: FontWeight.bold),),
),
),
],
),
),
),
),
);
}
}
class _SubCategoriesScreenState extends State<SubCategoriesScreen> {
void initState(){
super.initState();
if(widget.categoryId!=null && widget.subCategoryImagePath!=null && widget.subCategoryName!=null){
addSubCategory();
}
}
void addSubCategory(){
SubCategoryModel subCategoryModel=SubCategoryModel(
subCategoryId:widget.categoryId,
subCategoryImagePath: widget.subCategoryImagePath,
subCategoryName: widget.subCategoryName,
categoryColor: Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(0.5));
if(categoryModels!=null){
for (var categoryModel in categoryModels){
if (categoryModel.categoryId == subCategoryModel.subCategoryId){
categoryModel.subCategoryModels.insert(categoryModel.subCategoryModels.length-1,subCategoryModel);
}
}
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
title: BorderedText(
child:Text(
categoryModels[widget.categoryId].categoryName,
style: TextStyle(
color: Color(0XFFFFFB00),
fontSize: 30,
fontFamily: "Graduate"
),
),
strokeWidth: 5,
strokeColor: Colors.black,
),
elevation: 5,
backgroundColor: Color(0xFFF2C3D4).withOpacity(1),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
Navigator.pop(context);
},
iconSize: 40,
color: Color(0xFFA2000B),
),
actions: [
CircleAvatar(
radius: 27,
backgroundColor: Colors.transparent,
backgroundImage: AssetImage("images/cuttedlogo.PNG"),
)
],
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/logoBGopacity.png"),
fit: BoxFit.cover,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: GridView.builder(
scrollDirection: Axis.vertical,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount:categoryModels[widget.categoryId].subCategoryModels.length,
itemBuilder: (context,index){
if(categoryModels[widget.categoryId].subCategoryModels[index].subCategoryId==-1){
return EmptyCard(where: "subCategoryScreen");
}
return SubCategoryCard(subCategoryId:widget.categoryId,subcategoryName: categoryModels[widget.categoryId].subCategoryModels[index].subCategoryName,
subCategoryImagePath: categoryModels[widget.categoryId].subCategoryModels[index].subCategoryImagePath,
subCategoryColor: categoryModels[widget.categoryId].subCategoryModels[index].categoryColor,);
}
),
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: EdgeInsets.all(10),
child: Container(
decoration: BoxDecoration(
border: Border.all(style: BorderStyle.solid),
color: kColorTheme7,
borderRadius: BorderRadius.circular(40),
),
child: TextButton(
onPressed: (){
showModalBottomSheet(
context: context,
builder: (BuildContext context)=> AddMenuScreen(categoryId:widget.categoryId,buttonText: "Tarif Ekle", route:"subCategoryScreen"),
);
},
child: BorderedText(
strokeWidth: 5,
strokeColor: Colors.black,
child:Text("Tarif Ekle",style: TextStyle(
color: Colors.white,
fontFamily:'Graduate',
fontSize:30,
),
),
),
),
),
),
],
)
],
),
),
),
);
}
}
Error:
======== Exception caught by widgets library =======================================================
The following ArgumentError was thrown building SubCategoriesScreen(dirty, state: _SubCategoriesScreenState#72f75):
Invalid argument(s)
The relevant error-causing widget was:
SubCategoriesScreen file:///C:/Users/yagiz/AndroidStudioProjects/lezzet_kitabi/lib/screens/add_menu_screen.dart:121:98
When the exception was thrown, this was the stack:
#0 List.[] (dart:core-patch/growable_array.dart:254:60)
#1 _SubCategoriesScreenState.build (package:lezzet_kitabi/screens/subCategoriesScreen.dart:61:29)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4742:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4625:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4797:11)