I want to display the data obtained from futureBuilder into the table, this is the code that I tried but when I run browse an error appears like this
FutureBuilder(
future: UserController.getActivity(_selectedUser),
builder: (context, snapshot) {
if (snapshot.hasData != null) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, position){
var item = snapshot.data.elementAt(position);
return Container(
child: Table(
children: List<TableRow>.generate(10, (i) {
return TableRow(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0.5, color: Colors.grey))),
children: [
Container(
padding: EdgeInsets.all(18),
child: Text(
//data[i].author.toString(),
"${item["activity"]["project"]}",
style: TextStyle(
fontSize: 14,
color: Colors.black,
),
),
),
Container(
padding: EdgeInsets.all(18),
child: Text(
//data[i].stars.toString(),
item["created_at"],
style: TextStyle(
fontSize: 14,
color: Colors.black,
),
),
)
]);
})),
);
}
);
}
},
),
if I use listView in displaying data, it becomes ineffective because the data is a lot
Error is here at this line
itemCount: snapshot.data.length,
length is not found in the snapshot. You need to check the return type of future UserController what it's returning.
For being to verify your code that it's working fine you can set the default value
Just to verify that UI working fine
itemCount: 10
after that you need to check your return type.
Related
I have a StreamBuilder in order to build a Chat App, but there's an issue that it unexpectedly reloads with some events. At the time it reloads, the snapshot still got the same data in it, therefore some messages are repeatedly added to the List 'messages'.
How can I prevent the StreamBuilder from doing this repetition?
Here is my StreamBuilder code:
body: SingleChildScrollView(
reverse: true,
child: Center(
child: StreamBuilder(
stream: channel.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
addText(snapshot.data.toString(), 1); // adds to messages
}
return ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.only(top: 10, bottom: 10),
physics: NeverScrollableScrollPhysics(),
itemCount: messages.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.only(
left: 14, right: 14, top: 10, bottom: 10),
child: Align(
alignment: (messages[index].messageType == 'receiver'
? Alignment.topLeft
: Alignment.topRight),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: (messages[index].messageType == 'receiver'
? Colors.grey.shade200
: Colors.blue[200]),
),
padding: EdgeInsets.all(16),
child: Text(
messages[index].messageContent,
style: TextStyle(fontSize: 15),
),
),
),
);
},
);
},
),
),
),
create a List in your state class andif(snapshot.hasData){ List = snapshot.data; }
then use the items in your list instead of your snapshot;
I am trying to create a dialog to show a list of reviews on click event. However, the code below always generate an extra bottom padding after each gridview item and i was unable to find out which widget caused this extra padding.
Hopefully, someone can help me point me to the right direction. thanks much!
showDialog(
context: context,
builder: (_) {
return Dialog(
backgroundColor: Colors.orange[200],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
elevation: 16,
child: Container(
padding: EdgeInsets.only(bottom: 50),
child: StreamBuilder<QuerySnapshot>(
// stream: firestoreInstance.collection("requests").snapshots(),
stream: streamForReviews,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('');
case ConnectionState.waiting:
return new Text('');
default:
if (snapshot.hasError) {
return new Text('error');
}
if (snapshot.data != null) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
if (snapshot.data!.docs.length > 1) {
} else if (snapshot.data!.docs.length == 1) {
} else {}
});
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
),
scrollDirection: Axis.vertical,
shrinkWrap: true,
padding: EdgeInsets.zero,
// itemCount: snapshot.data.documents.length,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
// List rev = snapshot.data.documents.reversed.toList();
String comments =
snapshot.data!.docs[index].get("comments");
String reviewerName =
snapshot.data!.docs[index].get("name");
num rating = snapshot.data!.docs[index].get("rating");
String downloadURL =
snapshot.data!.docs[index].get("imageURL");
Timestamp reviewTimeStamp =
snapshot.data!.docs[index].get("createdDTG");
DateTime reviewDateTime =
DateTime.parse(reviewTimeStamp.toDate().toString());
DateFormat reviewDateTimeFormat =
new DateFormat('dd MMM yyyy');
String reviewDateTimeString =
reviewDateTimeFormat.format(reviewDateTime);
return Container(
padding: EdgeInsets.symmetric(
vertical: 20, horizontal: 20),
child: Column(
children: [
SizedBox(height: 10),
ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Image.network(
downloadURL,
fit: BoxFit.fitHeight,
height: 100,
),
),
SizedBox(width: 10),
Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment:
// CrossAxisAlignment.stretch,
children: [
Text(reviewDateTimeString,
style: TextStyle(
color: Colors.orange[800],
fontSize: 18,
// fontStyle: FontStyle.italic,
)),
SizedBox(height: 2),
Text(reviewerName,
style: TextStyle(
color: Colors.orange[800],
fontSize: 18,
)),
SizedBox(height: 2),
RichText(
text: TextSpan(
// style: Theme.of(context).textTheme.body1,
children: [
WidgetSpan(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 2.0),
child: Icon(
Icons.star,
color: Colors.orange,
size: 18,
),
),
),
TextSpan(
text: rating.toString(),
style: new TextStyle(
fontSize: 16.0,
color: Colors.orange[800],
),
),
],
),
),
SizedBox(height: 2),
],
),
Align(
alignment: Alignment.centerLeft,
child: Text(comments,
style: TextStyle(
color: Colors.orange[800],
fontSize: 16,
// fontStyle: FontStyle.italic,
)),
),
Divider(color: Colors.orange, thickness: 1),
],
),
);
},
);
} else {
return new Text('data null');
}
}
},
),
));
});
You need to change the value of childAspectRatio in SliverGridDelegateWithFixedCrossAxisCount widget. The default is 1, which means that grid items will have a width that is equal to their height. In your case, the width is approximately 2x of the height. your code should be like this:
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: 2, //try to change this number to see how it changes the dimensions of the grid item
i have two collection,
users collection
like collection.
in my like i have the list of like with there id, i am now using stream to fetch the list like user but. so if the user change his profile image it cant be updated in the like collection, so what i did is after fetching the list, i pass the id to another stream to get upadate from Users collection. this alot of bioler plate code. i am looking for way to combine this stream together.
here is a sample code
StreamBuilder(
stream: firestore
.collection('Matches')
.doc(auth.currentUser.uid)
.collection('Match')
.orderBy('chatTimeStamp').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container();
}
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.data.docs.isEmpty) {
return Align(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RippleAnimation(
repeat: true,
color: Colors.white,
minRadius: 100,
ripplesCount: 6,
child: Material(
elevation: 8.0,
shape: CircleBorder(),
child: CircleAvatar(
backgroundColor: themedata.darkTheme
? Colors.black
: Colors.white,
child: Image.asset(
'assets/1.png',
),
radius: 80.0,
),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'No Message Yet!',
textAlign: TextAlign.center,
style: GoogleFonts.raleway(
textStyle: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
),
],
),
);
}
return ListView.separated(
separatorBuilder: (_, index) => Padding(
padding:
EdgeInsets.only(left: 120.0, right: 40),
child: Divider(
color: Colors.white,
thickness: 1.0,
),
),
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
final data =
snapshot.data.docs[index].data()['Match'];
//here is where it depend on the value
return StreamBuilder(
stream: firestore
.collection('users')
.doc(data['id'])
.snapshots(),
builder: (context, snapshotid) {
final active = snapshotid.data.data();
if (snapshotid.hasError) {
return Container();
}
if (snapshotid.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator());
}
if (snapshotid.connectionState ==
ConnectionState.none) {
return Container();
}
if (!snapshotid.hasData) {
return Container();
}
For combining two streams you can use combine2 method from rxdart library. this library has all of the stream class features + some extra functionality which is really useful. for more detail you can see the official documentation here.
note: for using this library methods and functionalities you should also define streams by this library classes.
for example:
Stream stream, may be PublishSubject stream.
I am facing problem in using stream builder. Actually, I have a dropdown list and below it I have gridview to show product categories according to options chose in dropdown list. I have to use two stream builders, one for option(s) list in dropdown and other is for gridview. Dropdown is wroking fine but gridview is not changing data according to option choose in dropdown list.
Please help
My dropdown widget
Widget dropDownMenu({
required Size size,
BuildContext? context,}) {
return StatefulBuilder(builder: (context, setState) {
return FutureBuilder(
future: FirebaseFirestore.instance
.collection('options').get(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error while loading'));
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SpinKitFadingCircle(
itemBuilder: (BuildContext context, int index) {
return DecoratedBox(
decoration: BoxDecoration(
color: index.isEven
? MyStyles.themeData().primaryColor
: Colors.green,
),
);
},
),
);
}
if (snapshot.hasData && snapshot.data!.docs.isEmpty) {
return Center(child: Text('No Data'));
}
return Container(
height: size.height * 0.100,
padding: EdgeInsets.all(20.0),
color: Colors.white,
child: DropdownButton<String>(
dropdownColor: Colors.white,
elevation: 1,
value: viewModel.dropDownValue!,
hint: Text('Choose one option'),
items:
snapshot.data!.docs.map<DropdownMenuItem<String>>((value) {
return DropdownMenuItem<String>(
value: value.get('options'),
child: Text(
value.get('options'),
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
color: MyStyles.themeData().primaryColor,
fontSize: size.height * 0.024,
fontWeight: FontWeight.w600,
),
),
);
}).toList(),
onChanged: (value) {
setState(() {
viewModel.dropDownValue = value;
});
}),
);
},
);
});}
My gridview Widget
Widget buildGridView({Size? size, BuildContext? context}) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('categories')
.where('options', isEqualTo: viewModel.dropDownValue)
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error while loading'));
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SpinKitFadingCircle(
itemBuilder: (BuildContext context, int index) {
return DecoratedBox(
decoration: BoxDecoration(
color: index.isEven
? MyStyles.themeData().primaryColor
: Colors.green,
),
);
},
),
);
}
if (snapshot.hasData && snapshot.data!.docs.isEmpty) {
return Center(child: Text('No Categories available'));
}
return GridView.builder(
padding: const EdgeInsets.only(bottom: 70),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 1,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
),
itemCount: snapshot.data!.size,
itemBuilder: (BuildContext ctx, index) {
return GestureDetector(
onTap: () {},
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 3.0),
height: size!.height * 0.200,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Color(0x99C4C4C4),
blurRadius: 12,
offset: Offset(4, 4),
spreadRadius: 0,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: size.height * 0.120,
width: size.width * 0.120,
child: Image.network(
snapshot.data!.docs[index]['image'])),
SizedBox(height: size.height * 0.015),
Text(
snapshot.data!.docs[index]['name']!,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.poppins(
color: MyStyles.themeMode().textColor,
fontSize: size.height * 0.022,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
},
);
},
),
),
);}
I want to rebuild stream everytime I change options in dropdown. How can I achieve this?
I'm trying to display a list of employees in my app. Here's the code I got so far:
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 20,top: 20),
child: Container(
height: 40,
width: 120,
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.12),
borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(10),
child: Text("Employees",
style: TextStyle(
fontSize: 22,
color: Colors.black,
fontWeight: FontWeight.w600,
)),
),
),
),
StreamBuilder(
stream: Firestore.instance.collection("Employees").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: Text("Fetching data..."));
} else if(snapshot.connectionState == ConnectionState.done){
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data.documents[index]['name']));
},
);
} else {
return Text("hol up");
}
}),
],
);
When I run the app, it just shows 'Employees' and 'hol up' in a column. Why does the list of employees not show?
I solved the issue by simply adding shrinkWrap: true in my listview.
This should work. Also get the data from the indexed document.
ListTile(
title: Text(snapshot.data.documents[index].data['name']));