I'm trying to add a header item at the beginning of my list, so here is how I build it using firebase
new Expanded(
child: new StreamBuilder(
stream: Firestore.instance
.collection("users")
.document("dana")
.collection("Channels")
.snapshots(),
builder: (context, snapshot) {
return new ListView.builder(
scrollDirection: Axis.vertical,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) => _buildList(
context, snapshot.data.documents[index]),
);
}),
)
"_buildList" is just the Widget
Widget _buildListItem(BuildContext context, DocumentSnapshot document)
so I'm basically lost, I've no idea how to add another Widget as header
any suggestions?
You could return the "header" widget (the one you want above the listview but still in it) when the list is on index 0:
return new ListView.builder(
scrollDirection: Axis.vertical,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
if (index == 0) {
return someWidget, // return the widget you want as "header" here
} else {
return _buildList( context, snapshot.data.documents[index-1]),
}
}
);
Related
I'm currently trying to create a sliverlist that gets a list of user UID's from firebase then uses the streambuilder to find the information for each user. The problem is that is creates a bunch of sliverlists with a streambuilder listview inside so I have a bunch of items that are part of their own individual lists. How can I make this more efficiently to only build one sliverlist with all the item?
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return StreamBuilder(
stream: userSearch(context, snapshot.data['members'][index]),
builder: (context, snapshot) {
return ListView.separated(
shrinkWrap: true,
padding: const EdgeInsets.all(8),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return userWidget(
context,
snapshot.data[index],
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(),
);
},
);
},
childCount: snapshot.data['members'].length,
),
);
You can add NeverScrollableScrollPhysics() as the ScrollPhysics for the inner ListView.
It makes the ListView not scroll which means only the SliverList can scroll the items.
return ListView.separated(
physics: NeverScrollableScrollPhysics(), //Add this line
...
);
I am trying to fetch data from firebase to list all the documents in a listview builder the code is still not completed in term of displaying the database filed in the code. this is the error: The getter 'docs' isn't defined for the type 'Object'
Container(
child: StreamBuilder<Object>(
stream: _firestore
.collection('Patient')
.doc(_auth.currentUser.email)
.collection("Diabetes")
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
reverse: true,
shrinkWrap: true,
itemCount:
snapshot.data.docs.length, // here is the error "docs"
itemBuilder: (context, index) {
DocumentSnapshot documentSnapshot =
snapshot.data.docs[index]; // also another error "docs"
return Container();
});
}
return Center(
child: CircularProgressIndicator(),
);
}),
)
You should replace snapshot.data.docs.length with snapshot.data.length
Container(
child: StreamBuilder<Object>(
stream: _firestore
.collection('Patient')
.doc(_auth.currentUser.email)
.collection("Diabetes")
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
reverse: true,
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
DocumentSnapshot documentSnapshot = snapshot.data[index];
return Container();
});
}
return Center(
child: CircularProgressIndicator(),
);
}),
)
I solved the problem by replacing StreamBuilder<Object> with StreamBuilder<QuerySnapshot>. by default the StreamBuilder comes in this form StreamBuilder<Object>
After migrate to null-safety showing this error. What should I do now?
Widget chatMessages() {
return StreamBuilder(
stream: messageStream,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
padding: EdgeInsets.only(bottom: 70, top: 16),
itemCount: snapshot.data.docs.length,
reverse: true,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.docs[index];
return chatMessageTitle(
ds["message"], myUserName == ds["sendBy"]);
})
: Center(child: CircularProgressIndicator());
});
}
After adding null check (!) showing this error <the getter 'docs' is not defined for the type of object>
itemCount: snapshot.data!.docs.length,
reverse: true,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data!.docs[index];
You have to cast snapshot.data to its type. Suppose the type is QuerySnapshot (change this with the actual type of snapshot.data).
(snapshot.data! as QuerySnapshot).docs.length
Instead of typecasting at all locations, we can specify the type of stream in the StreamBuilder.
StreamBuilder<QuerySnapshot>(
...
);
Now snapshot.data is inferred as QuerySnapshot and no typecast is required.
snapshot.data!.docs.length
I have solved mine by adding StreamBuilder and builder(context, AsyncSnapshot snapshot).
Widget chatMessages() {
return StreamBuilder<QuerySnapshot>(
stream: messageStream,
builder: (context, AsyncSnapshot snapshot) {
return snapshot.hasData
? ListView.builder(
padding: EdgeInsets.only(bottom: 70, top: 16),
itemCount: snapshot.data.docs.length,
reverse: true,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.docs[index];
return chatMessageTitle(
ds["message"], myUserName == ds["sendBy"]);
})
: Center(child: CircularProgressIndicator());
});
}
There are a few solutions:
Provide a type to your StreamBuilder:
StreamBuilder<QuerySnapshot> (...)
Provide a type to the second parameter of your builder:
builder: (context, QuerySnapshot snapshot)
Use as to downcast:
(snapshot.data! as QuerySnapshot).docs['key']
Add error and connection state checks like this:
Widget chatMessages() {
return StreamBuilder(
stream: messageStream,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView.builder(
padding: EdgeInsets.only(bottom: 70, top: 16),
itemCount: snapshot.data.docs.length,
reverse: true,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.docs[index];
return chatMessageTitle(
ds["message"], myUserName == ds["sendBy"]);
});
});
}
I know there's probably a better way to do this but would like if its possible, to maintain the current DB structure.. (see attached)
DB Collections
Question: How can I return a StreamBuilder with a Listview(child:listTile) that displays profiles for all UID's that a particular user is following(eg: return user profiles that user "BHRaCBR.." is following). In this case im BHRaCBR...
Code below works but only returns one listTile (user):
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('following')
.doc('BHRaCBR..')
.collection('userFollowing')
.where('isApproved', isEqualTo: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('profile')
.where('uid', isEqualTo: ds['uid'])
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
final data0 = snapshot.data.docs;
return Container(
height: 200,
child: ListView.builder(
itemCount: data0.length,
itemBuilder: (BuildContext ctx, index) {
return Card(
child: ExpansionTile(
leading: CircleAvatar(
radius: 32,
backgroundImage: NetworkImage(
data0[index]
.data()['image_url']
.toString(),
),
),
title: Text(data0[index].data()['username']),
),
);
}),
);
});
});
});
buildComments() {
return StreamBuilder(
stream: commentRef
.document(postId)
.collection('comments')
.orderBy('timestamp', descending: false)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
List<Comment> comments = [];
snapshot.data.documents.forEach((doc) {
print(comments);
comments.add(Comment.fromDocument(doc));
});
return ListView(
children: comments,
);
});
}
I was trying to convert it in list view.builder but it gives me error you can can't use list instead of Widget, Can anyone solve this problem.
You should do the following:
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: EdgeInsets.all(8.0),
title: Text(snapshot.data.documents[index].data["name"]),
);
});
Assuming you have name in the document.