I am trying to take two streams of data from firebase and merge them into one, then use in my PageView builder in my flutter app. I have managed to get my first stream working (default occasions) but I now need to add another. Here are the two streams:
Stream<QuerySnapshot> getDefaultOccasions(BuildContext context) async*{
yield* Firestore.instance.collection('datestoremember').document('default').collection('Dates_to_Remember').snapshots();
}
Stream<QuerySnapshot> getPersonalOccasions(BuildContext context) async*{
final uid = await Provider.of(context).auth.getCurrentUID();
yield* Firestore.instance.collection('datestoremember').document(uid).collection('Dates_to_Remember').snapshots();
}
I'm not sure the best way to merge the two streams together and then use the result in a Page View Builder:
child: StreamBuilder(
stream: getDefaultOccasions(context),
builder: (context, snapshot) {
if(!snapshot.hasData) return const Text("Loading...");
return new PageView.builder(
itemCount: snapshot.data.documents.length,
controller: PageController(viewportFraction: 0.5),
onPageChanged: (int index) => setState(() => _index = index),
itemBuilder: (_, i) {
return Transform.scale(
scale: i == _index ? 1 : 0.5,
child: Card(
elevation: 6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(snapshot.data.documents[i]['Date'].toDate().day.toString()),
Text(DateFormat.MMMM()
.format(
formatter.parse(snapshot.data.documents[i]['Date'].toDate().toString()))
.toString()),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0),
child: FittedBox(
fit: BoxFit.contain,
child: Text(
snapshot.data.documents[i]['Title'],
overflow: TextOverflow.ellipsis,
),
),
)
],
),
),
);
},
);},
),
Here is all the code:
class AccountPage extends StatefulWidget {
#override
_AccountPageState createState() => _AccountPageState();
}
class _AccountPageState extends State<AccountPage> {
List<Category> _categories = [
Category('My History', Icons.history, MyHistory()),
Category('Dates to Remember', Icons.event_note, DatesToRemember()),
Category('Terms and Conditions', Icons.assignment, TermsandConditions()),
Category('Privacy Notice', Icons.security, PrivacyNotice()),
Category('Rate us', Icons.stars, RateUs()),
Category('Send us Feedback', Icons.feedback, GiveUsFeedback())
];
DateFormat formatter = DateFormat('dd-MM-yyyy');
int _index = 0;
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Container(
child: SizedBox(
height: 75, // card height
child: StreamBuilder(
stream: getDefaultOccasions(context),
builder: (context, snapshot) {
if(!snapshot.hasData) return const Text("Loading...");
return new PageView.builder(
itemCount: snapshot.data.documents.length,
controller: PageController(viewportFraction: 0.5),
onPageChanged: (int index) => setState(() => _index = index),
itemBuilder: (_, i) {
return Transform.scale(
scale: i == _index ? 1 : 0.5,
child: Card(
elevation: 6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(snapshot.data.documents[i]['Date'].toDate().day.toString()),
Text(DateFormat.MMMM()
.format(
formatter.parse(snapshot.data.documents[i]['Date'].toDate().toString()))
.toString()),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0),
child: FittedBox(
fit: BoxFit.contain,
child: Text(
snapshot.data.documents[i]['Title'],
overflow: TextOverflow.ellipsis,
),
),
)
],
),
),
);
},
);},
),
),
),
// SizedBox(height: 100.0,),
Container(
// Page Options
height: MediaQuery
.of(context)
.size
.height * 0.7,
child: ListView.builder(
itemCount: _categories.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
ListTile(
leading: Icon(
_categories[index].icon,
color: Colors.black,
),
title: Text(_categories[index].name),
trailing: Icon(Icons.arrow_forward_ios),
onTap: () =>
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
_categories[index].route)),
),
Divider(), // <-- Divider
],
);
}),
),
],
),
);
}
}
Stream<QuerySnapshot> getDefaultOccasions(BuildContext context) async*{
yield* Firestore.instance.collection('datestoremember').document('default').collection('Dates_to_Remember').snapshots();
}
Stream<QuerySnapshot> getPersonalOccasions(BuildContext context) async*{
final uid = await Provider.of(context).auth.getCurrentUID();
yield* Firestore.instance.collection('datestoremember').document(uid).collection('Dates_to_Remember').snapshots();
}
You can Merge your two Streams like this:
StreamGroup.merge([getDefaultOccasions(context), getPersonalOccasions(context)]).asBroadcastStream();
Related
I see that the stream builder returns ${globals.statusKey} as null, but I don't know why, because I can print the value out well, and the FriendStatus code is also a widget that I called well in another part of the app(which was drawer).
I can see these kinds of problem occurring frequently in stream builder but cannot find any solution.
There is an error like below
'package:cloud_firestore/src/firestore.dart': Failed assertion: line 63 ps 7:1 '! collectionPath.contains('//'):a collection path must not contain "//"
And here is the code.
body: SafeArea(
child: Container(
padding: EdgeInsets.fromLTRB(10, 5, 0, 0),
// child: SingleChildScrollView(
// scrollDirection: Axis.vertical,
child: Column(children: [
tapableDate(),
const SizedBox(
height: 10,
),
Container(
height: 220,
width: 330,
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
),
),
child: FriendStatus(),
),
Text(
"See \n statusKey: ${globals.statusKey} \n count: \n",
),
// Provider(create: (context) => TimerService(), child: EventList()),
// ),
]),
// ),
),
),
Code of FriendStatus.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:gw/globals.dart' as globals;
class FriendStatus extends StatefulWidget {
const FriendStatus({Key? key}) : super(key: key);
#override
State<FriendStatus> createState() => _FriendStatusState();
}
class _FriendStatusState extends State<FriendStatus> {
FirebaseFirestore firestore = FirebaseFirestore.instance;
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
padding: EdgeInsets.fromLTRB(20, 10, 20, 0),
child: Column(
children: [
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('user/${globals.currentUid}/friends')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>>
snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
final docs = snapshot.data!.docs;
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: docs.length,
itemBuilder: (context, index) {
return Container(
//padding:,
child: ListTile(
leading: Icon(
Icons.circle,
color: Colors.grey[850],
),
title: Text(docs[index]['name']),
));
},
);
},
)
],
)),
);
}
}
IM trying to use a stack where I displaying a listview and a
This is my code
#override
Widget build(BuildContext context) {
final user = Provider.of<Userforid>(context);
_deviceHeigth = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text(this.widget._receivername),
),
body: StreamBuilder<UserData>(
stream: DatbaseService(uid: user.uid).userData,
builder: (context, snapshot) {
return _conversationPageUI();
},
),
);
And then the _conversationPageUI(); is this here
Widget _conversationPageUI() {
return Builder(builder: (BuildContext _context) {
return Stack(
overflow: Overflow.visible,
children: <Widget>[
_messageLisView(),
Align(
alignment: Alignment.bottomCenter,
child: _messageField(_context),
),
],
);
});
}
And then this each widgets are here
Widget _messageLisView() {
final user = Provider.of<Userforid>(context);
return Container(
width: _deviceWidth,
child: StreamBuilder<Conversation>(
stream: DatbaseService.instance
.getConversation(this.widget._convertsationID),
builder: (BuildContext _context, _snapshot) {
if (_listViewController.hasClients) {
_listViewController.animateTo(
_listViewController.position.maxScrollExtent,
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut);
}
var _conversationData = _snapshot.data;
if (_conversationData != null) {
if (_conversationData.messages != null) {
return ListView.builder(
controller: _listViewController,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
itemCount: _conversationData.messages.length,
itemBuilder: (BuildContext _context, int _index) {
var _message = _conversationData.messages[_index];
bool _isOwnMessage = _message.senderID == user.uid;
return _messageListViewChild(_isOwnMessage, _message);
},
);
} else {
return Align(
alignment: Alignment.center,
child: Text("Let's start a Conversation"),
);
}
} else {
return Center(
child: Container(
child: CircularProgressIndicator(),
));
}
},
),
);
}
Widget _messageField(BuildContext _context) {
return Container(
height: _deviceHeigth * 0.07,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
border: Border.all(color: Colors.black, width: 2)),
margin: EdgeInsets.symmetric(
horizontal: _deviceWidth * 0.04, vertical: _deviceHeigth * 0.03),
child: Form(
key: _formKey,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
_messageTextField(),
_sendMessageButton(_context),
_videoMessageButton(),
],
),
),
);
}
The _messageField is just a Textformfield with a hintext and 2 icons . Heres how it looks
So as you can see I cannot see the last listview item correctly and thats my question how can I fix that ?
Padding(
padding: const EdgeInsets.only(bottom:MediaQuery.of(context).size.height * 0.1),
child: ListView.builder(
controller: _listViewController,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
itemCount: _conversationData.messages.length,
itemBuilder: (BuildContext _context, int _index) {
var _message = _conversationData.messages[_index];
bool _isOwnMessage = _message.senderID == user.uid;
return _messageListViewChild(_isOwnMessage, _message);
},
),
)
//OR
sizedBox(
height: MediaQuery.of(context).size.height * 0.80,
child: ListView.builder(
controller: _listViewController,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
itemCount: _conversationData.messages.length,
itemBuilder: (BuildContext _context, int _index) {
var _message = _conversationData.messages[_index];
bool _isOwnMessage = _message.senderID == user.uid;
return _messageListViewChild(_isOwnMessage, _message);
},
),
)
just add padding to the bottom of listview:
Widget _messageLisView() {
final user = Provider.of<Userforid>(context);
return Container(
padding: EdgeInsets.only(bottom: 100),
width: _deviceWidth,
I think passing
fit: StackFit.expand,
to your stack widget will fix your problem.
1.This is the first page i need to run This code runs initially and give
The 'length' was called on null.
Receiver: null
Tried calling: length
Type error but after clicks gesture it runs perfectly i need run this code before gesture detector calls
I tried without gesture detector but it not works.
class ProductPage extends StatefulWidget {
#override
_ProductPageState createState() => _ProductPageState();
}
class _ProductPageState extends State<ProductPage> {
String id=' RN62p5KZAtk48mGL2n66';
int selectedIndex = 0;
String district;
bool loading = false;
_ProductPageState();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 30.0,),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: SizedBox(
height: 25,
child:StreamBuilder<List<CategoryModel>>(
stream: DatabaseService().getCategories(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => buildCategory(
index,
snapshot.data[index].categoryName,
snapshot.data[index].id
)
);
},
),
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('district').snapshots(),
builder: (context, snapshot) {
return Container(
padding: EdgeInsets.only(bottom: 16.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.fromLTRB(12.0, 10.0, 10.0, 10.0),
child: Text(
"District",
),
)),
new Expanded(
flex: 4,
child: DropdownButton(
value: district,
isDense: true,
onChanged: (valueSelectedByUser) {
setState(() {
this.district = valueSelectedByUser;
});
print(district);
},
hint: Text('Sort By District'),
items: snapshot.data.docs
.map((DocumentSnapshot document) {
return DropdownMenuItem<String>(
value: document.data()['Name'],
child: Text(document.data()['Name'] ),
);
}).toList(),
),
),
],
),
);
}),
district == null ? Expanded(
flex: 1,
child: StreamBuilder<List<SubCategoryModel>>(
stream:DatabaseService().getSubCategories(id),
builder: (context,snapshot){
if(!snapshot.hasData){
return Center(
child: CircularProgressIndicator(),
);
}else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return PostContainer(
id: snapshot.data[index].listId,
likes: snapshot.data[index].likes,
views: snapshot.data[index].views,
imageUrl: snapshot.data[index].imageUrl,
longitude: snapshot.data[index].longitude,
latitude: snapshot.data[index].latitude,
providerName: snapshot.data[index].providerName,
providerTel: snapshot.data[index].providerTel,
units: snapshot.data[index].units,
description: snapshot.data[index].description,
unitPrice: snapshot.data[index].unitPrice,
name: snapshot.data[index].name,
date: snapshot.data[index].date,
providerId: snapshot.data[index].providerId,
categoryId: snapshot.data[index].categoryId,
providerImage: snapshot.data[index].providerImage,
district: snapshot.data[index].district,
address: snapshot.data[index].address,
);
}
);
}
},
),
):
Expanded(
flex: 1,
child: StreamBuilder<List<SubCategoryModel>>(
stream: DatabaseService().getSortedSubCategories(id, district),
builder: (context,snapshot){
if(!snapshot.hasData){
return Center(
child: CircularProgressIndicator(),
);
}else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return PostContainer(
id: snapshot.data[index].listId,
likes: snapshot.data[index].likes,
views: snapshot.data[index].views,
imageUrl: snapshot.data[index].imageUrl,
longitude: snapshot.data[index].longitude,
latitude: snapshot.data[index].latitude,
providerName: snapshot.data[index].providerName,
providerTel: snapshot.data[index].providerTel,
units: snapshot.data[index].units,
description: snapshot.data[index].description,
unitPrice: snapshot.data[index].unitPrice,
name: snapshot.data[index].name,
date: snapshot.data[index].date,
providerId: snapshot.data[index].providerId,
categoryId: snapshot.data[index].categoryId,
providerImage: snapshot.data[index]
.providerImage,
district: snapshot.data[index].district,
address: snapshot.data[index].address,
);
}
);
}
},
),
),
],
)
);
}
Widget buildCategory(int index,String categoryName,String catId) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
id= catId;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
categoryName,
style: TextStyle(
fontWeight: FontWeight.bold,
color: selectedIndex == index ? Color(0xFF535353) : Color(0xFF535353),
),
),
Container(
margin: EdgeInsets.only(top: 20 / 4), //top padding 5
height: 2,
width: 30,
color: selectedIndex == index ? Colors.black : Colors.transparent,
)
],
),
),
);
}
Future<void> _shoeerror() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Thank you For Join with Us !'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Row(
children: [
Text('Select the Category to proceed '),
],
)
],
),
),
actions: <Widget>[
TextButton(
child: Text('OK'),
onPressed: () {
setState(() {
id=' RN62p5KZAtk48mGL2n66';
});
},
),
],
);
},
);
}
}
2.this is the database call function
Stream<List<SubCategoryModel>> getSubCategories(docId) {
return _db.collection('categories').doc(docId).collection('subCategories').snapshots().map((snapshot) =>
snapshot.docs.map((doc) => SubCategoryModel.fromJson(doc.data())).toList());
}
I suspect this is being executed on each build with a side effect... perhaps recreating the stream back to its initial state:
stream: DatabaseService().getCategories()
For the "Builder" widgets expecting a future or a stream, you need to create what they are watching as a value outside the build() method... perhaps in an initState, or my favorite, in a Riverpod provider.
Also, you don't seem to have any conditional based on the non-null value of snapshot.data, so it will blow up because of .length. This is expected behavior. :)
I am building a Flutter app and I have a screen with 2 ListViews. The data source is a firestore database and it is the same for both list however one list presents only an image while the other list presents the image PLUS other information.
I have managed to found a solution to display both List however it does not seem the most effective because I believe I am downloading the same data 2 time. Do you have any suggestion on how to make it better???
See my code below
final _firestore = Firestore.instance;
class ItemPage extends StatefulWidget {
#override
_ItemPageState createState() => _ItemPageState();
}
class _ItemPageState extends State<ItemPage> {
bool showSpinner = false;
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
heroTag: 'itemppage',
transitionBetweenRoutes: false,
middle: Text(
appData.categoryName,
style: kSendButtonTextStyle,
),
),
child: Scaffold(
backgroundColor: kColorPrimary,
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Column(
children: <Widget>[
Expanded(
child: ItemList(),
),
Container(
height: 80.0,
child: ItemListBottomScroll(),
)
],
),
),
),
);
}
}
class ItemList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('books')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text(
'Loading...',
style: kSendButtonTextStyle,
);
default:
return new PageView(
scrollDirection: Axis.horizontal,
children:
snapshot.data.documents.map((DocumentSnapshot document) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(10.0),
child: Stack(
children: <Widget>[
CachedNetworkImage(
imageUrl: document['url'],
placeholder: (context, url) =>
new CircularProgressIndicator(),
errorWidget: (context, url, error) =>
new Icon(Icons.error),
width: MediaQuery.of(context).size.width - 20,
height:
(MediaQuery.of(context).size.width - 20),
fit: BoxFit.cover),
Positioned(
bottom: 0.0,
right: 0.0,
child: IconButton(
color: kColorAccent.withOpacity(0.8),
iconSize: 50.0,
icon: Icon(Icons.add_circle),
onPressed: () {
print(document['name'] +
document.documentID +
' clicked');
},
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(
left: 10.0, right: 10.0, bottom: 10.0),
child: Row(
children: <Widget>[
Expanded(
child: Text(
document['name'],
style: kSendButtonTextStyle,
),
flex: 3,
),
Expanded(
child: Text(
appData.currency + document['price'],
textAlign: TextAlign.right,
style: kDescriptionTextStyle,
),
flex: 1,
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: Container(
child: Text(
document['description'],
style: kDescriptionTextStyle,
),
width: double.infinity,
),
)
],
),
);
}).toList(),
);
}
},
);
}
}
class ItemListBottomScroll extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('books')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return new ListView(
scrollDirection: Axis.horizontal,
children:
snapshot.data.documents.map((DocumentSnapshot document) {
return Stack(
children: <Widget>[
Container(
height: 80.0,
width: 90.0,
padding: EdgeInsets.only(left: 10.0),
child: GestureDetector(
onTap: () {
print(document['name'] +
document.documentID +
' bottom clicked');
},
child: new CachedNetworkImage(
imageUrl: document['url'],
placeholder: (context, url) =>
new CircularProgressIndicator(),
errorWidget: (context, url, error) =>
new Icon(Icons.error),
fit: BoxFit.cover),
),
),
],
);
}).toList(),
);
}
},
);
}
}
In order to read both info from the same Stream you need to expose it as a broadcast stream first:
final streamQuery = _firestore
.collection('books')
.snapshots()
.asBroadcastStream();
return StreamBuilder<QuerySnapshot>(
stream: streamQuery,
builder: ...
I am wondering how to get data from firestore to flutter app using the streambuilder. I created the necessary Boilerplate code I have the widget built and working and in the below code
headimageassetpath is nothing but a URL string which exists in the firestore.
#override
Widget build(BuildContext context) {
return Scaffold(
body:
new StreamBuilder(
stream: Firestore.instance.collection('Items').snapshots(),
builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
var items = snapshot.data?.documents ?? [];
return new Lost_Card(
headImageAssetPath : snapshot.data.documents.map()(['url'],)
);
},
)
My firestore:
full code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class LostPage extends StatefulWidget {
#override
_LostPage createState() => new _LostPage();
}
class _LostPage extends State<LostPage> {
//temp vars
final String firebasetest = "Test";
//firestore vars
final DocumentReference documentReference =
Firestore.instance.document("Items/Rusty");
//CRUD operations
void _add() {
Map<String, String> data = <String, String>{
"name": firebasetest,
"desc": "Flutter Developer"
};
documentReference.setData(data).whenComplete(() {
print("Document Added");
}).catchError((e) => print(e));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:
new StreamBuilder(
stream: Firestore.instance.collection('Items').snapshots(),
builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
var items = snapshot.data?.documents ?? [];
return new Lost_Card(
headImageAssetPath : snapshot.data.documents.map()(['url'],)
);
},
)
/*new Lost_Card(
headImageAssetPath: "https://i.imgur.com/FtaGNck.jpg" ,
title: "Mega Dish",
noro: "old",
)*/,
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: _add),
);
}
}
class Lost_Card extends StatelessWidget
{
//All the card variables
final String headImageAssetPath;
final IconData icon;
final Color iconBackgroundColor;
final String title;
final String noro;
final int price;
final ShapeBorder shape;
Lost_Card({
this.headImageAssetPath, //used
this.icon,
this.iconBackgroundColor,
this.title, //used
this.noro, //used
this.price,
});
#override
Widget build(BuildContext context) {
// TODO: implement build
return GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
children: <Widget>[
Card(
child: Column(
// mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 4,
width: MediaQuery.of(context).size.height / 2.5,
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
headImageAssetPath),
fit: BoxFit.cover),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: FractionalOffset.topLeft,
child: CircleAvatar(
backgroundColor: Colors.redAccent,
radius: 15.0,
child: Text(
noro,
textScaleFactor: 0.5,
),
),
),
),
Align(
alignment: FractionalOffset.topRight,
child: Container(
color: Colors.blueAccent,
height: 35.0,
width: 35.0,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.account_circle),
Text(
"1P",
textScaleFactor: 0.5,
),
],
),
),
),
),
],
),
),
Center(
child: Container(
padding: const EdgeInsets.all(8.0),
alignment: FractionalOffset.bottomCenter,
child: Text(
title,
style: TextStyle(
fontWeight: FontWeight.w700,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FlatButton(
child: Text(
"Add To Cart",
style: TextStyle(color: Colors.grey[500]),
),
onPressed: () => null,
),
Text(
"\$5",
style: TextStyle(color: Colors.grey[500]),
)
],
)
],
),
),
],
);
}
}
Actual App
Please shed some light on this. Tks.
This should work for one item
body: new StreamBuilder(
stream: Firestore.instance.collection("collection").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text(
'No Data...',
);
} else {
<DocumentSnapshot> items = snapshot.data.documents;
return new Lost_Card(
headImageAssetPath : items[0]["url"]
);
}
If you want to create list builder from many documents use it like this
return new ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return new Lost_Card(
headImageAssetPath : ds["url"];
);
Accessing documents using StreamBuilder in Flutter 2
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('products').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return Text(doc['name']);
});
} else {
return Text("No data");
}
},
)
As per new changes 2021 in Firebase FireStore you can retrieve data from collection using StreamBuilder as below
final _mFirestore = FirebaseFirestore.instance;
return StreamBuilder<QuerySnapshot>(
stream:
_mFirestore.collection(kFirebaseCollectionName).snapshots(),
builder: (context, snapshots) {
if (!snapshots.hasData) {
return Center(
child: Text('Data not available',),
);
}
final messages = snapshots.data.docs;
List<Text> textWidgets = [];
messages.forEach((element) {
final messageText = element['text'];
final messageSender = element['sender'];
final textWidget = Text('$messageText, $messageSender');
textWidgets.add(messageBubbleWidget);
});
},
);
Card buildItem(DocumentSnapshot doc) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'name: ${doc.data['name']}',
style: TextStyle(fontSize: 24),
),
Text(
'todo: ${doc.data['todo']}',
style: TextStyle(fontSize: 20),
),
Text(
'Age: ${doc.data['age']}',
style: TextStyle(fontSize: 10),
),
SizedBox(
height: 12,
),
],
)
],
),
),
); }
For other persons who will face the same problem, the card and stream builder will represent a solution. The Widget has the Card just before it declaration and has inside the body the next part:
body: ListView(
padding: EdgeInsets.all(8),
children: <Widget>[
Form(
key: _formKey,
child: buildTextFormField(),
),
StreamBuilder<QuerySnapshot>(
stream: db
.collection('CRUD')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList());
} else {
return SizedBox();
}
},
)
],
),
Update for 2022, Flutter 2.10, cloud_firestore: ^3.1.11. You can retrieve data from collection using StreamBuilder
Stream collectionStream = FirebaseFirestore.instance.collection('users').snapshots();
StreamBuilder<QuerySnapshot>(
builder: (context, snapshot) {
if (snapshot.hasData) {
final messages = snapshot.data!.docs;
List<Text> messageWidgets = [];
for (var element in messages) {
final messageText = element['text'];
final messageSender = element['sender'];
final messageWidget =
Text('$messageText from $messageSender');
messageWidgets.add(messageWidget);
}
return Column(
children: messageWidgets,
);
}
return const Text('Error');
},
stream:collectionStream),
StreamBuilder<List<UData>>(
stream: AdminData().getDrivers,
builder: (context, snapshot) {
return ListView(
children: snapshot.data.map((document) {
return hadCard(
widget: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
hadText(title: document.name),
hadText(title: document.phone),
hadText(title: document.Driver),
],
),
);
}).toList(),
);
}),