I got a page in flutter than contains future builder, and the result of it displayed in list view builder. When I get small amount of data, flutter display the data without any problem. But when I get large amount of data, it display nothing.
What I get from this problem is when I get large amount of data, future builder hasn't finished get the data before the page is shown.
How can I make the page wait for the future finished to get the data before the page is shown?
Thanks
FutureBuilder<List<SalesTable>>(
future: SelectSalesTable.getSalesTable(widget.kodesales,
daterange1.format(widget.tgl1), daterange2.format(widget.tgl2)),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none) {
return new Text('No Data..!!');
} else if (snapshot.connectionState == ConnectionState.waiting) {
return new Center(child: CircularProgressIndicator());
} else {
if (snapshot.hasData) {
List<SalesTable> data = snapshot.data;
return Container(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Card(
shadowColor: Colors.grey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 10,
child: Padding(
padding:
const EdgeInsets.fromLTRB(5, 10, 5, 10),
child: ListTile(
title: Text(
data[index].name +
' | ' +
data[index].Category,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold)),
subtitle: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text(
'Date : ' +
dateformat3.format(
data[index]
.date1),
style: TextStyle(
fontWeight:
FontWeight.bold)),
)
],
),
],
),
onTap: () {},
),
),
),
),
],
);
},
itemCount: data.length,
),
],
));
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
}
return Center(child: CircularProgressIndicator());
},
)
Related
I am trying to pass firebase snapshot data from first page to second page in flutter using GET. I'm able to pass data from one screen to another in debug mode but not in release mode.
I have used a streambuilder on the page and a Future on second . Please where am i going wrong ?
here is code..
first page:
Container(
child: Expanded(
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection('Songs')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return Container(
color: Colors.white24,
padding: EdgeInsets.all(10),
child: ListView(
children: snapshot.data!.docs.map((document) {
return Container(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
side: BorderSide(
color: Colors.purple, width: 2)),
elevation: 4,
child: ListTile(
title: Text(document['title'],
style: TextStyle(fontSize: 16)),
subtitle: Text(
document['artist'],
style: TextStyle(color: Colors.purple),
),
onTap: () {
Get.to(() => DetailsPage(
piss: document,
post: document.id,
));
},
contentPadding: EdgeInsets.all(20),
leading: Image.asset('assets/logo.png'),
trailing: document['isNew'] == true
? Image.asset(
'assets/new.gif',
)
: null),
),
);
}).toList(),
),
);
}),
),
),
_banner == null
? Container()
: Container(
margin: const EdgeInsets.only(bottom: 12),
height: 52,
child: AdWidget(
ad: _banner!,
),
),
],
),
),
);
}
}
second page
FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Expanded(
child: ListView.builder(
itemCount: widget.piss['tileHeaders'].length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
setState(() {
_index = index;
counter = counter + 1;
print('COUNTER: $counter');
if (counter == 3) {
_showRewardedAd();
_controller.play();
print("Counter is $counter");
counter = 0;
_createRewardedAd();
}
});
index > 0
? playIt(index)
: _controller
.load(widget.piss['videos'][index]);
},
child: Card(
elevation: 5,
child: Column(
children: [
Container(
height: 100,
child: Row(
children: [
Center(
child: Padding(
padding: EdgeInsets.all(10),
child: Expanded(
child: Image.asset(
"assets/logo.png"),
flex: 2,
// flex: 2,),
),
)),
Expanded(
child: Container(
alignment:
Alignment.topLeft,
child: Column(
children: [
Expanded(
flex: 5,
child: ListTile(
title: Text(
widget.piss[
'tileHeaders']
[index],
style: TextStyle(
fontSize:
26)),
),
),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment:
MainAxisAlignment
.end,
children: [
Container(
child: widget
.piss[
'videos']
[
index]
.toString()
.contains(
'PL')
? Center(
child:
Container(child: playlist()),
)
: Center(
child:
Container(
child:
notPlaylist(),
),
),
),
],
))
],
)),
)
],
))
],
)),
);
}),
);
}
})
Please help
I want to show API data in the list view.
enter image description here
listview looks like this.
Future<List<Post>> getData() async {
final response = await http.get(
Uri.parse("http://192.168.0.9:8000/api/buildingdata/"),
headers: {"Access-Control-Allow-Origin": "*"});
if (response.statusCode == 200) {
List list = (json.decode(utf8.decode(response.bodyBytes)));
var postList = list.map((element) => Post.fromJson(element)).toList();
return postList;
} else {
throw Exception('Failed to load post');
}
}
class Post {
final String buildingName;
final String buildingLoc;
final String buildingCall;
Post({this.buildingName, this.buildingLoc, this.buildingCall});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
buildingName: json["building_name"],
buildingLoc: json["building_loc"],
buildingCall: json["building_call"],
);
}
I used this code to get API data to the app.
enter image description here
and my API looks like this. (Ignore image for each building)
_makeDataList(List<Map<String, dynamic>> datas) {
return ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 10),
itemBuilder: (BuildContext _context, int index) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
children: [
Expanded(
child: Container(
height: 100,
padding: const EdgeInsets.only(left: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
datas[index]["building_name"].toString(),
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 15),
),
SizedBox(height: 5),
Text(
datas[index]["building_loc"].toString(),
style: TextStyle(
fontSize: 12, color: Colors.black.withOpacity(0.3)),
),
SizedBox(height: 5),
],
),
),
)
],
),
);
},
separatorBuilder: (BuildContext _context, int index) {
return Container(height: 1, color: Colors.pink.withOpacity(0.4));
},
itemCount: datas.length,
);
}
Widget _bodyWidget() {
return FutureBuilder(
future: postList,
builder: (BuildContext context, dynamic snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Center(
child: Text("Failed to load data"),
);
}
if (snapshot.hasData) {
return _makeDataList(snapshot.data);
}
return Center(child: Text("No data for this location"));
});
}
This is my code I want to use for listview, but this error occurs when I run app.
type 'List<Post>' is not a subtype of type 'List<Map<String, dynamic>>'
When I tried basic listview code(only shows building name), it worked well.
return ListView.builder(
itemCount : snapshot.data.length,
itemBuilder : (context,index){
Post post = snapshot.data[index];
return Card(
child: ListTile(
title:Text(post.buildingName)
)
);
},
);
Well this code is just for checking connection with API, so I don't use this code.
where should I change to fix this error?
You have to change List<Map<String,dynamic>> to List<Post> to your _makeDataList
_makeDataList(List<Post> datas) {
return ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 10),
itemBuilder: (BuildContext _context, int index) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
children: [
Expanded(
child: Container(
height: 100,
padding: const EdgeInsets.only(left: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
datas[index].building_name.toString(),
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 15),
),
SizedBox(height: 5),
Text(
datas[index].building_loc.toString(),
style: TextStyle(
fontSize: 12, color: Colors.black.withOpacity(0.3)),
),
SizedBox(height: 5),
],
),
),
)
],
),
);
},
separatorBuilder: (BuildContext _context, int index) {
return Container(height: 1, color: Colors.pink.withOpacity(0.4));
},
itemCount: datas.length,
);
}
Widget _bodyWidget() {
return FutureBuilder(
future: postList,
builder: (BuildContext context, dynamic snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Center(
child: Text("Failed to load data"),
);
}
if (snapshot.hasData) {
return _makeDataList(snapshot.data);
}
return Center(child: Text("No data for this location"));
});
}
I have a problem with using Visibility widget.
What I want to do is hiding certain listview's by depending user's click on my Row. But when User click on row, all Listview is showing. When clicked again, all listview widget's are going away.
What I want to do is with images:
This is how my page looks
This is what happens when I click on arrow button or "Sezon 1" Text
This is what I want to do when I click on arrow button or "Sezon 1" Text
What I'm trying to do is When I click Season 2, it will show season 2 episodes. When I click season 3 it will show season 3 episodes etc.
Here is my code (I know It's a little messy for right now, apologize for that) :
GestureDetector is working same for every click.
bool viewVisible = false;
void hideWidget() {
setState(() {
viewVisible = !viewVisible;
print(viewVisible);
});
StreamBuilder<QuerySnapshot>(
stream: seasons.snapshots(),
builder:
(BuildContext context, AsyncSnapshot asyncSnapshot) {
if (asyncSnapshot.hasError) {
return Center(
child:
Text('Error'));
} else {
if (asyncSnapshot.hasData) {
List<DocumentSnapshot> listOfDocumentSnap =
asyncSnapshot.data.docs;
return Padding(
padding: const EdgeInsets.only(top: 0, left: 0),
child: Align(
alignment: Alignment.topLeft,
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: listOfDocumentSnap.length,
itemBuilder: (context, index) {
var episodes = firestore
.collection('shows')
.doc(data.id)
.collection('Seasons')
.doc(listOfDocumentSnap[index].id)
.collection('Episodes');
return Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(
top: 0, left: 18, right: 18),
child: GestureDetector(
onTap: () {
hideWidget();
},
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
8),
border: Border.all(
color: Colors.pink)),
child: Row(
children: [
SizedBox(
width: 20,
),
Text(
listOfDocumentSnap[index]
.get('name')
.toString()
.toUpperCase(),
style: TextStyle(
fontSize: 20,
color:
Colors.grey[800],
fontWeight:
FontWeight.w700),
),
Spacer(flex: 1),
Icon(
Icons.arrow_drop_down,
size: 45,
color: Colors.pink,
),
],
),
),
),
),
StreamBuilder<QuerySnapshot>(
stream: episodes.snapshots(),
builder: (BuildContext context,
AsyncSnapshot asyncSnapshot) {
if (asyncSnapshot.hasError) {
return Center(
child: Text(
'Error'));
} else {
if (asyncSnapshot.hasData) {
List<DocumentSnapshot>
listOfDocumentSnap =
asyncSnapshot.data.docs;
return Padding(
padding:
const EdgeInsets.only(
top: 5, left: 18.0),
child: Visibility(
visible: viewVisible,
child: Align(
alignment:
Alignment.topLeft,
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount:
listOfDocumentSnap
.length,
itemBuilder:
(context,
index) {
return ListTile(
onTap: () {
setState(
() {
selectedIndex =
index;
});
},
trailing:
Icon(Icons
.play_arrow),
title: Text(listOfDocumentSnap[
index]
.id
.toString()),
);
/* return Text(
listOfDocumentSnap[
index]
.get(
'name'));*/
},
),
],
),
),
),
);
} else {
return Center(
child:
CircularProgressIndicator());
}
}
},
),
SizedBox(
height: 30,
)
],
);
},
),
],
),
),
);
} else {
return Center(child: CircularProgressIndicator());
}
}
},
),
Sorry, I did not check what is wrong with your code. But, instead of writing your own hide/show logic for each row, try to use Flutter's ExpansionTile widget. It will handle the expanded/collapsed states for you:
https://medium.com/flutterdevs/expansion-tile-in-flutter-d2b7ba4a1f4b
There are two different way I know to handle widget visibility. Create a bool to switch visibility. I'm using _show.
Using if condition
inside (column or any widget)
if (_show) Container(),
Using Visibility Widget
Column(
children: [
Visibility(
visible: _show,
child: Container(),
),
)
I'm creating an interface from an api data everything works fine, but when I add a value to my list of TextEditingController the error of "RangeError (index): Invalid value: Only valid value is 0: 1" appear and I do not know why Is happening this if you could help me I'll be grateful
this is my code.
List<TextEditingController> openQuest = List<TextEditingController>();
Widget _questions(){
return FutureBuilder(
future: widget.questSect,
builder: (BuildContext context, AsyncSnapshot snapshot){
if(snapshot.hasData){
return Container(
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index){
if(snapshot.data[index]['tipo_pregunta'] == 2){
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
SizedBox(height:5),
Container(
width: MediaQuery.of(context).size.width * .88,
child: Text(
snapshot.data[index]['pregunta'],
textAlign: TextAlign.left,
style: TextStyle(
color: SECONDARY_TEXT,
fontSize: 16,
)
),
),
SizedBox(height: 5),
],
),
);
}else{
openQuest.add(TextEditingController());
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
SizedBox(height:5),
Container(
width: MediaQuery.of(context).size.width * .88,
child: Text(
snapshot.data[index]['pregunta'],
textAlign: TextAlign.left,
style: TextStyle(
color: SECONDARY_TEXT,
fontSize: 16,
)
),
),
SizedBox(height: 5),
InputCustom(
cont: openQuest.length < 0 ? TextEditingController() : openQuest[index],
icono: null,
labelText: null,
validate: (String val){
if(val.isEmpty){
return 'Se debe contestar la pregunta';
}
return null;
},
max: 100,
)
],
),
);
}
},
),
);
}else if(snapshot.hasError){
return Center(
child: Text('Error al traer las preguntas.'),
);
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Obteniendo preguntas...'),
)
]
),
);
},
);
}
From a quick look I think the problem lies in this line
cont: openQuest.length < 0 ? TextEditingController() : openQuest[index],
You have created the openQuest and only adding one item to the list. But as of your condition
itemBuilder: (BuildContext context, int index){
if(snapshot.data[index]['tipo_pregunta'] == 2){
any value other than 2 the index is passed on to the else part which can be greater than the length of openQuest and your openquest list only has one element... try changing that to something like openQuest[openQuest.length - 1]
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']));