Display more than a ListView in a flutter widget - flutter-provider

I am working on my first flutter application and I have been facing a problem.
I have a riverpod StreamProvider giving back a stream of objects that I return in a ConsumerWidget:
return currentEntries.when(
data: (entries) {
return ListView.separated(
itemCount: entries.length,
itemBuilder: (context, index) {
return MyListItem(item: entries[index]);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(),
);
},
error: (error, stackTrace) => Center(child: Text(error.toString())),
loading: () => const Center(child: CircularProgressIndicator()),
);
Now I want to have other Widgets in my page than just the ListView.
I have tried putting the ListView within a Columns just for test:
return Column(
children: const [
Text('Another widget comes here.'),
Expanded(child: MyListViewWidget()),
],
);
It works when I wrap MyListViewWidget into an Expanded. As I side effect it scrolls beneath the text, what I don't want. The Text widget it just a placeholder.
If I remove Expanded, I then get an error.
How can I have the list view and other widgets within a parent widget?
The list view is built based upon a riverpod StreamProvider.
In fact I intend to put a horizontal ListView with fixed number of items above the vertical ListView generated based upon the StreamProvider.

Exapned widgets helps or you can wrap your widgets with fixed size SizedBox
the problem is all about the list has no limitation of size so when you wrap it with fixed sized widget you can use it whenever you want

Related

how to add elements to Listview.builder without rebuilding all the previous items

i use Listview.builder with a List of items in flutter ,
when the user scroll down i listen the the scroll controller than
i get more data from firebase Firestore
the problem that when more data added to the itemlist
all the previous items of the Listview.builder rebuilded automaticaly
ex : the list.lenght is 50 ,when i scroll down i get 20 more items and add them to the item list ,
the 50 previous item are reubilded automaticaly (like the image )
enter image description here
this make the app bugging some times
any help ?
this is my Listview.builder code
Selector<postsPage_modelView,Tuple2<List<Post>,bool>>(
selector: (_,provider)=>Tuple2(provider.postsList, provider.isLoading),
builder: (_,data,__)=>ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: data.item1.length+1,
itemBuilder: (context,index){
if(index == data.item1.length){
if(data.item2) {
return const Center(
child: CircularProgressIndicator()
);
}
return const Center();
}
Post tmp = data.item1[index];
return PostItem(post: tmp);
},
),
),
thank you all

Show a different list in Firebase Animated List by changing child path

I am quite new to firebase and flutter. I am trying to show a new list in the firebase animated list by changing the database reference child path. Though I am able to make changes in the firebase database, the list doesn't change to the other child.
This is my database model. I want to first show children of Test-one in the app and after pressing a button it should show the children of Test-two.
Future<void> db()async{
item = Item("", "");
final FirebaseDatabase database = FirebaseDatabase.instance();
setState(() {
itemRef = database.reference().child(Test);
itemRef.onChildAdded.listen(_onEntryAdded);
itemRef.onChildChanged.listen(_onEntryChanged);
});
}
On a button press I use setstate to change path from "Test-one" to "Test-two". The string "Test" stores the current string name and when the button is pressed using setstate the other child is selected like if "Test-one" is the current path it becomes "Test-two". Though I am able to add data to the new location that is "Test-two" but the list still shows the children from "Test-one"
The function below is used for displaying data.
Flexible(
child: FirebaseAnimatedList(
query: itemRef,
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return new FutureBuilder<DataSnapshot>(
builder: (BuildContext context, snapshot){
return new ListTile(
leading: Icon(Icons.message),
title: Text(items[index].title),
subtitle: Text(items[index].body),
);
},
);
},
),
),

Streambuilder is not updating in Flutter

I am using Streambuilder and loading Snapshot from firebase. After loading the snapshot, I am putting my data into Post.dart where I made widget structure. My code can get the data, but when I delete the one of the post from the firebase, it still show the same posts, but last one disappears instead of the deleted one. However, if I change my page and come back, right one is deleted and everything is fine. So I think flutter knows that I am changing my firebase, but does not know how to map it into my Post. Any thought?
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("timeline")
.doc(widget.currentUser.id)
.collection('timelinePosts')
.orderBy('timestamp', descending: true)
.snapshots()
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> streamSnapshot) {
var items = streamSnapshot.data != null &&
streamSnapshot.data.docs != null
? streamSnapshot.data.docs
: [];
List<Post> posts =
items.map((doc) => Post.fromDocument(doc)).toList();
return !streamSnapshot.hasData ||
streamSnapshot.connectionState ==
ConnectionState.waiting
? Center(
child: CircularProgressIndicator(),
)
: Column(
children: posts);
})
and Post is something like
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
...
],
);
}
You need to provide a unique key to your post item widgets so that when flutter rebuilds the column, it is able to differentiate between the old posts and the new list of posts. Basically it has to do with how flutter decides to rebuild certain elements and when.
If you want to test whether a unique key can solve the problem I usually start by assigning a key like this to the post widgets:
key: Key("${Random().nextDouble()}"),
And seeing if that changes anything. If it fixes it, you can try a more efficient key like a combination of the properties of each element.
I might be a bit late to drop my 2 cents, but you can try to add this code to your Post Widget:
#override
void didUpdateWidget(Post oldWidget) {
//add the code you want it to update inside your Post widget.
super.didUpdateWidget(oldWidget);
}

StreamBuilder with flutter_firebase has null value on second widget build (image disappears)

I managed to show images from firestore using streambuilder on a page, but the problem is that the image disappears (I get a null snapshot.data value) if I go back to the last page and come back.
Here is my code. How can I make the snapshot data persist, so the image stays there and doesn't disappear when the widget rebuilds?
Container(child: Column(
children: [
Text(' Certifications',
Container(child: StreamBuilder(
stream: certificates,
builder: (context, snapshot) {
return !snapshot.hasData
? Center(child: Container(
child: Center(child: Text(
'No images yet'))))
: Container(
child: GridView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
url = snapshot.data.documents[index].get('url');
return Container(child: FadeInImage
.memoryNetwork(fit: BoxFit.cover,
placeholder: kTransparentImage,
image: url),
),
);
}),
);
}),
),
Streams are asynchronous. which means StreamBuilder does not get old snapshots, only new future snapshots. This is your problem.
When your widget is re-built it is subscribing to a stream that has already had events. Yes you would think that data in the snapshot should be the last event value, but that is not the case. It will be null until a new event is pushed onto your certificates stream.
So one solution is for the service that is loading your certificates to store the value of the initial API request and make that available for you to use in your StreamBuilder's initialData property.
I would structure it like this:
StreamBuilder(
stream: certificateService.stream,
initialData: certificateService.value, // <-----
builder: ...
)
Hope this points you in the right direction.

Flutter Listview duplicates random element instead of adding new element on new data

I'am trying to create something like feed with Flutter and Firebase and I want to order posts by their 'postedAt' value but the problem is when I use collection.orderBy() it is not working properly. It adds new post to the random place at the feed and gives it a imageURL of random existing post (or I think it just duplicates one item in the feed). I created indexes at Firebase I tried both index types none working. The strange thing is, when I'm adding new post from the phone when my adding completed it just works fine but when listing on the other phone it shows described behaviour.
Edit: when I hot reload it works correct (last added post shows up on the top)
Edit: when I removed the orderBy method problem continued.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser.uid)
.collection("posts")
.orderBy('postedAt', descending:true)
.snapshots(),
builder: (BuildContext context,AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
print("error:" + snapshot.error.toString());
}
List<Post> posts = [];
posts = snapshot.data.docs.map((postDoc) {
return Post.fromDoc(postDoc);
}).toList();
if (posts.isEmpty) {
return Center(
child: Text("No posts"),
);
}
return ListView.builder(
cacheExtent: 4000,
itemCount: posts.length,
itemBuilder: (BuildContext context, int index) {
return PostWidget(
post: posts[index],
);
},
);
},
)
my indexes:
Composite index
single index
screenshot of the document:
document ss
I solved this issue.
I thought that if it is duplicating the elements, may be it cannot seperate them. and added key paramater to PostWidget so it worked.

Resources