how to use two future builder in one page in flutter - flutter

In my Flutter app, I need to display two lists that are coming from the database, but I am having trouble getting both lists to display on the same screen. I am using two FutureBuilder widgets, but the first list is displaying correctly while the second list is still loading.
Here is the code I am using:
var future1 = FutureBuilder<List<QuranTextModel>>(
future: database.getQuranText(),
builder: (context, snapshot) {
if(snapshot.hasData){
return ScrollablePositionedList.builder(
itemScrollController: scrollToIndex,
itemCount: snapshot.data!.length,
initialScrollIndex: widget.position,
itemBuilder: (context, index) {
// Build the list item widget here
});
}else{
return const Center(child: CircularProgressIndicator(),);
}
}
);
var future2 = FutureBuilder<List<UrduTextModel>>(
future: database.getUrduTranlation(),
builder: (context, snapshot) {
if(snapshot.hasData){
return ScrollablePositionedList.builder(
itemScrollController: scrollToIndex,
itemCount: snapshot.data!.length,
initialScrollIndex: widget.position,
itemBuilder: (context, index) {
// Build the list item widget here
});
}else{
return const Center(child: CircularProgressIndicator(),);
}
}
);
Column(
children: [
SizedBox(
height: 200,
child: future1,
),
SizedBox(
height: 200,
child: future2,
),
],
)
The first FutureBuilder is used to build a list of QuranTextModel objects, and the second FutureBuilder is used to build a list of UrduTextModel objects. I am using a Column widget to display both lists, with each list contained within a SizedBox widget to give it a fixed height.
The issue I am having is that only the first list is displaying correctly, while the second list is still loading. How can I get both lists to display on the same screen?
Thank you for any help you can provide!

SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 200,
child: future1),
SizedBox(height: 200,child: future2,)
],
),
),
Try this.
also you have to check your future status before populate you can check that by using
if (snap.connectionState == ConnectionState.done) { your code. you can check does snpa has data in it. }
connection state has deferent states that can help you to make your UI more interactive

Related

What widget should I use?

This is what I am doing now.
Main Page:
I would like to make it same like this picture.Example:
I have tried couple ways and widget to build it but couldn't figure it out. Also, I want to retrieve the data from the Firebase and show them as the content.
Code 1: https://pastebin.com/A0nK1riQ
Code 2: https://pastebin.com/i1T7gBNy
Widget build(BuildContext context) {
return Container(
child: StreamBuilder(
stream: _products.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (streamSnapshot.hasData) {
return ListView.builder(
itemCount: streamSnapshot.data!.docs.length,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
return Container(
margin: const EdgeInsets.all(10),
child: ListTile(
title: Text(documentSnapshot['name']),
subtitle: Text(documentSnapshot['price'].toString()),
trailing: SizedBox(
width: 100,
),
),
);
});
}
return SizedBox.shrink();
}),
);
}
You may use GridView.builder
https://api.flutter.dev/flutter/widgets/GridView-class.html
and in gridview build use column
According to me, first you have to check which NavigationRail icon clicked then put the condition on it's GestureDetector like
// global variable
String itemClickedValue = "";
then set the value in it according to user click
itemClickedValue = "first";
then check the condition while fetching data like
if(itemClickedValue.compareTo("first") == 0){
// pass that documentId or api and then show in list
}

AnimatedList out of range when StreamBuilder refreshes

StreamBuilder(
stream: users.where("invites", arrayContains: uid).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
_items = snapshot.data!.docs;
return AnimatedList(
key: listKey,
initialItemCount: _items.length,
itemBuilder: (context, index, animation) {
return _buildItem(index, _items[index], animation);
},
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Center(
child: SizedBox(
height: 50,
width: 50,
child: CupertinoActivityIndicator()),
),
],
);
}
},
)
I got this StreamBuilder with a stream from FirebaseFirestore. E.g. I have 3 entries in Firebase which match my condition (saved in _items). So far, so good. But if I delete one of those, the stream refreshes but the list throw an error: RangeError (index): Invalid value: Not in inclusive range 0..1: 2
Other way round same problem: Only two are shown and the third is not shown.
Does anyone have an idea why or how to fix this.
Thanks :)
This does not work with Animated List because your index is decreasing. You need to build a new Animated List or I would recommend to use a normal list view.

how to use getx obx instead of future builder for a displaying a list of images

I'm trying to display a list of images stored in my firebase cloud storage. I have the image name stored in my firestore. and my getURL() function gets the download url as a future for the respective image.
Using future builder I'm successful in displaying the list. I'm trying to achieve the same thing using Obx GetX. The problem is flutter is trying to display the images before the URL is retrieved. How do I successfully return a future of a widget in my second approach
ListView.builder(
itemCount: deviceListController.devices[index].images !=
null
? deviceListController.devices[index].images!.length
: 0,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (context, imageIndex) {
return SizedBox(
height: 100,
width: 100,
child: FutureBuilder(
future:
deviceListController.getURL(index, imageIndex),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return CircularProgressIndicator();
case ConnectionState.done:
return Image.network(deviceListController
.devices[index].imageURL[imageIndex]!);
// case ConnectionState.none:
// case ConnectionState.active:
default:
return Icon(Icons.accessible_forward);
}
},
),
);
},
),
here is my attempt at this. the problem is I dont know how to return/implement a future in the obx style.
Obx(
() => ListView(
scrollDirection: Axis.horizontal,
children: deviceListController.devices[index].images!
.asMap()
.map((ind, image) {
deviceListController.getURL(index, ind);
return MapEntry(
ind, Image.network(device.imageURL[ind]!));
})
.values
.toList()),
),
Edit: This is closest I could come up with. and it still doesnt load the images. flutter is looking for images before the async task is done.
Obx(() {
return deviceListController.devices[index].images !=
null
? ListView(
scrollDirection: Axis.horizontal,
children: deviceListController
.devices[index].images!
.asMap()
.map((ind, image) {
pageState(AppState.loading);
deviceListController.getURL(index, ind);
pageState(AppState.loaded);
return pageState.value == AppState.loading
? MapEntry(
ind,
Image.network(
device.imageURL[ind]!))
: MapEntry(
ind, CircularProgressIndicator());
})
.values
.toList())
: Spacer();
}),
Try using an enum for your state management.
enum AppState { initial, loading, loaded, error, empty, disabled }
Rx<AppState> pageState = AppState.initial.obs;
pageState(AppState.loading);
await some time taking operation.
pageState(AppState.loaded);
Obx(
() => pageState.value == AppState.loading
? Center(child: CircularProgressIndicator())
: YOUR WIDGET
here, you can use an enum to create state, and show the widgets based on the state ready.

Flutter Firebase only let certain data be shown on list view builder

I am trying to only display certain data from a collection. In my example, I only want to show data in the list where the collection in name on firebase is equal to the name of the widget. I am unable to solve this problem
Expanded(
child: Container(
child: FutureBuilder(
future: getPosts(),
builder: (_,snapshot){
if(snapshot.data["name"]== widget.info.name){
return ListView.builder(
itemCount:
x,
itemBuilder: (_,index){
return ListTile(
title: Text(snapshot.data[index].data["name"]),
);
});
Expanded(
child: Container(
child: FutureBuilder(
future: getPosts(),
builder: (_,snapshot){
return ListView.builder(
itemCount:
snapshot.data,
itemBuilder: (_,index){
if(snapshot.data["name"]== widget.info.name){
return ListTile(
title:Text(snapshot.data[index].data["name"]),
);
}else{
return Container();
}
})}))
);
A better option will be to pass the widget name in the getPosts() function you defined and update the firebase query to do the filtering. This way it be much faster as firebase does the require indexing and will do the filtering in O(len(filtered_elements)) rather than current time complexity of O(len(all_elements)).

Combine itemBuilder with StickyHeader in Flutter

I'm new to flutter and I want to organise the elements that I get from Firestore in a list with StickyHeaders. I would like to do it with an itemBuilder and the snapshot I get from the database.
My problem is the itemBuilder builds each item separately and has to be returned, but StickyHeader needs to have all items added as children.
How can I achieve this? Just as a reference I paste my code without the StickyHeader. buildItemBubble returns a Card Widget.
StreamBuilder(
stream: buildSnapshots(_filters),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(
child: CircularProgressIndicator(),
);
return snapshot.data.documents.length == 0
? Center(child: Text('It\s empty here...'))
: CupertinoScrollbar(
child: ListView.builder(
key: new PageStorageKey('randomkey'),
shrinkWrap: true,
padding: const EdgeInsets.all(10.0),
itemCount: snapshot.data.documents.length,
itemBuilder: (ctx, i) =>
buildItemBubble(snapshot, i),
),
);
},
)