How to use Stack and listview together flutter - flutter

I have a ListView.builder inside of FutureBuilder where I get and display DB data to a screen.
Data are displayed one by one, but I'm wondering how to use the Stack widget in order to display them on each other.
https://github.com/geekruchika/FlutterCardSwipe that's how elements have to be positioned(scroll down)
SOLVED:
#override
Widget build(BuildContext context) {
var device = MediaQuery.of(context).size;
return FutureBuilder<List<Task>>(
future: DBHelper().getTasks(),
builder: (BuildContext context, AsyncSnapshot<List<Task>> snapshot) {
if (snapshot.hasData) {
var data = snapshot.data;
return snapshot.data.length > 0
? Stack(
children: data.map((task) {
return Positioned(
child: Dismissible(
key: UniqueKey(),
crossAxisEndOffset: -0.1,
onDismissed: (direction) {
DBHelper().delete(task.id);
},
child: Container(
height: device.height * 585 / 812,
child: AddTask(null, task.name,
'Meeting with directory', null, []),
),
),
);
}).toList(),
)
: Container(
height: device.height * 585 / 812,
child: NoTasksFound(),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}

What you tried is correct except for you had to convert Iterable to a List.
Like:
Widget build(BuildContext context) {
var device = MediaQuery.of(context).size;
return FutureBuilder<List<Task>>(
future: DBHelper().getTasks(),
builder: (BuildContext context, AsyncSnapshot<List<Task>> snapshot) {
if (snapshot.hasData) {
var data = snapshot.data;
return Stack(
children: snapshot.data.map((task) { // map the data
return Positioned(
child: Dismissible(
key: UniqueKey(),
crossAxisEndOffset: -0.2,
background: Container(color: Colors.red),
onDismissed: (direction) {
// DBHelper().delete(task.id);
},
child: Container(
// margin: EdgeInsets.only(bottom: 100, top: 100),
height: device.height * 585 / 812,
child: AddTask(null, 'Description',
'Meeting with directory', null, []),
),
),
);
}).toList(), // convert the mapped iterable to list
);
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}
Hope that helps!

Related

Flutter streambuilder returns wrong titles

I recieve ’title’ from firebase in a streambuilder but it gets all titles from all documents. I just want titles from the selected document.
StreamBuilder(
stream: Firestore.instance
.collection(widget.user.uid)
.orderBy('date', descending: true)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasData) {
return ListView(
shrinkWrap: true,
children: snapshot.data.documents.map((document) {
final current = document.data;
final activities = current["activities"] as List;
List titles =
activities.map((e) => e["title"]).toList();
return Center(
child: Container(
width:
MediaQuery.of(context).size.width / 1.2,
height:
MediaQuery.of(context).size.height / 6,
child: Text("Title: $titles"),
),
);
}).toList(),
);
}
return const Text("no data");
},
)
What am I doing wrong? I just want to display title: lkjn and title:99okkj in a listview.
Just wrap widget creation inside of activitites.map(...) operation and make your widget list flat
Here is the updated version of the build method:
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
shrinkWrap: true,
children: snapshot.data.documents.map((document) {
final current = document.data;
final activities = current["activities"] as List;
return activities.map((e) => Center(
child: Container(
width:
MediaQuery.of(context).size.width / 1.2,
height:
MediaQuery.of(context).size.height / 6,
child: Text("Title: ${e["title"]}"),
),
)
);
}).expand((element) => element).toList(),
));
}

How to display array of image from firestore in listview flutter.?

I want to display array image from firebase but I get the following errors:
Errors:
Illegal scheme character (at character 13)
NetworkImage("https://firebasestorage.googleapis.com/v0/b/online-shop-98ea4...
NetworkImage("1", scale: 1.0)
NetworkImage("h", scale: 1.0)
Code:
ListView.builder(
itemBuilder: (context, index) {
for (int i = 0;
i <
snapshot.data.documents[index]
.data()['images']
.length;
i++) {
_listOfImages.add(NetworkImage(
snapshot.data.documents[index].data()['images'][i]));
}
return Column(
children: [
Container(
child: CarouselSlider(
options: CarouselOptions(),
items: _listOfImages
.map((item) => Container(
child: Center(
child: Image.network(item.toString(),
fit: BoxFit.cover, width: 1000)),
))
.toList(),
),
)
],
);
// ignore: dead_code
},
itemCount: _item.length,
);
var x;
fetchData(){
QuerySnapshot querySnapshot = await Firestore.instance
.collection("user_category")
.document(uidCur)
.collection('categories')
.getDocuments();
//put your snapshot query here
x = querySnapshot.documents;
}
#override
Widget build(BuildContext context) {
ListView.builder(
itemCount : x.length;
itemBuilder: (context, index) =>
return Column(
children: [
Container(
child: CarouselSlider(
options: CarouselOptions(),
items: x
.map((item) => Container(
child: Center(
child:
Image.network(item.toString(),
fit: BoxFit.cover, width:
1000)),
))
.toList(),
),
)
],
);
// ignore: dead_code
},
);
}

How to load more items to a list when reach the bottom of results flutter

I have the code below which feed a list with 10 results from firebase. In this case it shows only the 10 items, now I wanna, when user gets the bottom of results, it loads more 10 items and add it to the list. I already have the scrollController and it works.. I receive the log "LOAD HERE" when I get the bottom of the results.
My doubt is how to add the new 10 items in the list?
scrollListener() async {
if (scrollController.position.maxScrollExtent == scrollController.offset) {
print('LOAD HERE');
}
}
#override
void initState() {
scrollController.addListener(scrollListener);
super.initState();
}
#override
void dispose() {
scrollController.removeListener(scrollListener);
super.dispose();
}
loadList(submenu ,callback, context, deviceSize){
return FutureBuilder(
future: ctrlLab.loadList(submenu, 10),
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.error != null) {
print(snapshot.error);
return Center(child: Text('ERROR!'));
}else {
return GridView.builder(
padding: EdgeInsets.all(10.0),
controller: scrollController,
itemCount: snapshot.data.length,
itemBuilder: (ctx, i) {
Item item = snapshot.data[i];
if (i < snapshot.data.length) {
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
background: Container(
padding: EdgeInsets.all(10.0),
color: Colors.grey[800],
child: Align(
alignment: AlignmentDirectional.centerEnd,
child: Icon(
Icons.delete,
color: Colors.white,
size: 40,
),
),
),
onDismissed: (DismissDirection direction) {
ctrl.onDismissed(callback, item);
},
child: GestureDetector(
child: Card(
elevation: 5.0,
child: Padding(
padding: EdgeInsets.all(10.0),
child: GridTile(
child: Hero(
tag: "${item}",
child: item.imageUrl == null
? setIconLab(item)
: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: setIconLab(item),
placeholder: (ctx, url) =>
Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Image.asset('assets/images/noPhoto.jpg',
fit: BoxFit.cover),
),
),
footer: Container(
padding: EdgeInsets.all(8.0),
color: Colors.white70,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.name
),
),
],
),
),
),
),
),
),
);
}
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCountAndLoading(
itemCount: snapshot.data.length + 1,
crossAxisCount: deviceSize.width < 600 ? 2 : 3,
childAspectRatio: 0.7,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
),
);
}
},
);
}
Infinite Scrolling in ListView
I have achieved this case by using the local field instead of getting data from firebase. Hope it will give you some idea.
import 'package:flutter/material.dart';
class ListViewDemo extends StatefulWidget {
ListViewDemo({Key key}) : super(key: key);
#override
_ListViewDemoState createState() => _ListViewDemoState();
}
class _ListViewDemoState extends State<ListViewDemo> {
ScrollController controller;
int count = 15;
#override
void initState() {
super.initState();
controller = ScrollController()..addListener(handleScrolling);
}
void handleScrolling() {
if (controller.offset >= controller.position.maxScrollExtent) {
setState(() {
count += 10;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List view'),
),
body: ListView.builder(
controller: controller,
itemCount: count,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Item $index'),
);
},
),
);
}
#override
void dispose() {
controller.removeListener(handleScrolling);
super.dispose();
}
}
You have to add another 10 data to the crtLap.loadList(subMenu, 20) and call setState inside the scrollListener to rebuild the widget about the changes.
var data = crtLap.loadList(subMenu, 10);
scrollListener() async {
if (scrollController.position.maxScrollExtent == scrollController.offset) {
setState((){
data = crtLap.loadList(subMenu, 20);
});
}
}
and use this data field to the FutureBuilder directly,
loadList(submenu ,callback, context, deviceSize){
return FutureBuilder(
future: data,
builder: (ctx, snapshot) {
.....
...
..
}

Class 'String' has no instance method 'map'

I am using the flutter carousel code and trying to add images from firebase.
This is my code:
class FullscreenSliderDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF030164),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('quotes').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading data... Please Wait');
final double height = MediaQuery.of(context).size.height;
return Container(
height: 100.0,
padding: const EdgeInsets.all(4.0),
child: new ListView(
scrollDirection: Axis.horizontal,
children: snapshot.data.documents
.map<Widget>((DocumentSnapshot document) {
return CarouselSlider(
options: CarouselOptions(
height: height,
viewportFraction: 1.0,
enlargeCenterPage: false,
),
items: (document.data()['img']).map(
(item) => Container(
child: Center(
child: Image.network(
item,
fit: BoxFit.cover,
height: height,
)),
),
).toList());
}).toList(),));
},
),
);
}
}
I am getting the error Class 'String' has no instance method 'map'. and I'm not sure how to resolve this. If anyone could help, I would appreciate it!
I think you're looking for something like this:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF030164),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('quotes').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading data... Please Wait');
final double height = MediaQuery.of(context).size.height;
return CarouselSlider(
options: CarouselOptions(
height: height,
viewportFraction: 1.0,
enlargeCenterPage: false,
),
items: snapshot.data.documents
.map<Widget>((document) {
return Container(
child: Center(
child: Image.network(
document.data()['img'],
fit: BoxFit.cover,
height: height,
)
),
),
).toList()
)
)
},
),
);
}
With this you have only one CarouselSlider for all documents/images, instead of a separate one for each document.

How to loop the PopupMenuItem in PopupMenuButton in Flutter?

I want to display values from my API in a PopupMenuItem in PopupMenuButton. I manage to display it but I want it to be dynamic. Currently, I hard-coded the index of each item because it seems that I cannot do looping inside PopupMenuButton.
`Widget _simplePopup4() => PopupMenuButton<int>(
child: Icon(Icons.arrow_drop_down, color: Colors.orangeAccent),
offset: Offset(0, 100),
itemBuilder: (context) => [
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[1].title); //index 1
}
}
return CircularProgressIndicator();
})),
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[2].title); //index 2
}
}
return CircularProgressIndicator();
})),
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[3].title); //index 3
}
}
return CircularProgressIndicator();
})),
),
],
);`
//First attempt which gives error: RenderShrinkWrappingViewport does not support returning intrinsic dimensions.
Widget _simplePopup5() => PopupMenuButton(
itemBuilder: (context) {
var list = List<PopupMenuEntry<Object>>();
list.add(
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.setTitle.length,
itemBuilder:
(BuildContext context, int index) {
return Text(snapshot.data.setTitle[index].title);
});
}
}
return CircularProgressIndicator();
})),
),
);
list.add(
PopupMenuDivider(
height: 10,
),
);
return list;
},
icon: Icon(
Icons.settings,
size: 50,
color: Colors.white,
),
);
//Second attempt which gives error: Another exception was thrown: A RenderFlex overflowed by 85 pixels on the bottom.
Widget _simplePopup5() => PopupMenuButton(
itemBuilder: (context) {
var list = List<PopupMenuEntry<Object>>();
list.add(
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final listTitle = <Widget>[];
for (var i = 0;
i < snapshot.data.setTitle.length;
i++) {
listTitle.add(SingleChildScrollView(
scrollDirection: Axis.vertical,
child: InkWell(
child:
Text(snapshot.data.setTitle[i].title),
)));
}
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Column(children: listTitle);
}
}
return CircularProgressIndicator();
})),
),
);
list.add(
PopupMenuDivider(
height: 10,
),
);
return list;
},
icon: Icon(
Icons.settings,
size: 50,
color: Colors.white,
),
);
From the screenshot, only one item are clearly displayed which is "MR" while the other item (before item "MR") are displayed in half. Meanwhile, the rest of the item (after item "MR") being replaced with error message.
The screenshot of the second attempt error
The cause of the RenderFlex error is because the child Widget expands beyond the parent Widget. What you can do here is fetch the List of PopupMenu items prior to rendering the PopupMenuButton. With this approach, the List items is ready prior to clicking the PopupMenuButton.