I am trying to create a dialog to show a list of reviews on click event. However, the code below always generate an extra bottom padding after each gridview item and i was unable to find out which widget caused this extra padding.
Hopefully, someone can help me point me to the right direction. thanks much!
showDialog(
context: context,
builder: (_) {
return Dialog(
backgroundColor: Colors.orange[200],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
elevation: 16,
child: Container(
padding: EdgeInsets.only(bottom: 50),
child: StreamBuilder<QuerySnapshot>(
// stream: firestoreInstance.collection("requests").snapshots(),
stream: streamForReviews,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('');
case ConnectionState.waiting:
return new Text('');
default:
if (snapshot.hasError) {
return new Text('error');
}
if (snapshot.data != null) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
if (snapshot.data!.docs.length > 1) {
} else if (snapshot.data!.docs.length == 1) {
} else {}
});
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
),
scrollDirection: Axis.vertical,
shrinkWrap: true,
padding: EdgeInsets.zero,
// itemCount: snapshot.data.documents.length,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
// List rev = snapshot.data.documents.reversed.toList();
String comments =
snapshot.data!.docs[index].get("comments");
String reviewerName =
snapshot.data!.docs[index].get("name");
num rating = snapshot.data!.docs[index].get("rating");
String downloadURL =
snapshot.data!.docs[index].get("imageURL");
Timestamp reviewTimeStamp =
snapshot.data!.docs[index].get("createdDTG");
DateTime reviewDateTime =
DateTime.parse(reviewTimeStamp.toDate().toString());
DateFormat reviewDateTimeFormat =
new DateFormat('dd MMM yyyy');
String reviewDateTimeString =
reviewDateTimeFormat.format(reviewDateTime);
return Container(
padding: EdgeInsets.symmetric(
vertical: 20, horizontal: 20),
child: Column(
children: [
SizedBox(height: 10),
ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Image.network(
downloadURL,
fit: BoxFit.fitHeight,
height: 100,
),
),
SizedBox(width: 10),
Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment:
// CrossAxisAlignment.stretch,
children: [
Text(reviewDateTimeString,
style: TextStyle(
color: Colors.orange[800],
fontSize: 18,
// fontStyle: FontStyle.italic,
)),
SizedBox(height: 2),
Text(reviewerName,
style: TextStyle(
color: Colors.orange[800],
fontSize: 18,
)),
SizedBox(height: 2),
RichText(
text: TextSpan(
// style: Theme.of(context).textTheme.body1,
children: [
WidgetSpan(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 2.0),
child: Icon(
Icons.star,
color: Colors.orange,
size: 18,
),
),
),
TextSpan(
text: rating.toString(),
style: new TextStyle(
fontSize: 16.0,
color: Colors.orange[800],
),
),
],
),
),
SizedBox(height: 2),
],
),
Align(
alignment: Alignment.centerLeft,
child: Text(comments,
style: TextStyle(
color: Colors.orange[800],
fontSize: 16,
// fontStyle: FontStyle.italic,
)),
),
Divider(color: Colors.orange, thickness: 1),
],
),
);
},
);
} else {
return new Text('data null');
}
}
},
),
));
});
You need to change the value of childAspectRatio in SliverGridDelegateWithFixedCrossAxisCount widget. The default is 1, which means that grid items will have a width that is equal to their height. In your case, the width is approximately 2x of the height. your code should be like this:
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: 2, //try to change this number to see how it changes the dimensions of the grid item
Related
In my home screen my app shows carousel first then a vertical list of challenges cards retrieved from Cloud Firestore using GridView.builder as follows:
GridView.builder(
scrollDirection: Axis.vertical,
itemCount: _challenges.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 4),
),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
if (_challenges[index]["isLocked"] == "true") {
showLockedDialog();
} else {
checkParticipation(index);
if (checkPart == true) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
ChallengeDetails(_challenges[index])));
}
checkPart = true;
}
},
child: Stack(
children: [
Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image(
image: NetworkImage(_challenges[index]["image-path"]),
fit: BoxFit.cover,
height: 150,
width: 350,
opacity: _challenges[index]["isLocked"] == "true"
? AlwaysStoppedAnimation(.4)
: null,
),
),
),
Center(
child: Text(
"${_challenges[index]["name"]}\n",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
Center(
child: Text(
"\n${_challenges[index]["date"]}",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
textDirection: TextDirection.ltr,
)),
Center(
child: SizedBox(
height: 130,
width: 130,
child: _challenges[index]["isLocked"] == "true"
? Image.asset("assets/lock-icon.jpg")
: null,
),
)
],
),
);
});
Everything retrieving fine and it is rendered in my home_screen as follows:
body: Column(
children: [
AdsBanner(),
SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.only(right: 8, left: 8, bottom: 5),
child: Row(
children: [
Text(
AppLocalizations.of(context)!.challenges + " ",
style: TextStyle(fontSize: 20),
),
Text(
AppLocalizations.of(context)!.clickToParticipate,
style: TextStyle(fontSize: 15),
)
],
),
),
Expanded(child: ChallengeCard()),
],
),
The problem is that only the GridView area is scrolling and what am seeking for is to scroll the whole screen with the GridView area, I was trying to use the CustomScrollView() but its not working properly.
I'll be thankful for any help.
First in your GridView.builder add these:
GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
...
)
then in your home_screen wrap your column with SingleChildScrollView:
SingleChildScrollView(
child: Column(
children: [
AdsBanner(),
SizedBox(
height: 30,
),
Padding(
...
),
),
You can provide physics: NeverScrollableScrollPhysics() on GridView to disable scroll effect. If you want scrollable as secondary widget use primary: false, to have Full Page scrollable, you can use body:SingleChildScrollView(..) or better using body:CustomScrollView(..)
I want the photos taken on the same date to be in the same group.
This is my gallery
I want this
Future<List<VideoImageDataModel>> fetchPhotos() async {
var dataList = await Historydao().ImageData();
return dataList;
}
FutureBuilder<List<VideoImageDataModel>>(
future: fetchPhotos(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var photoList = snapshot.data;
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: (10 / 10), crossAxisCount: 4),
itemCount: photoList?.length,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: EdgeInsets.fromLTRB(5, 5, 0, 0),
//padding: EdgeInsets.fromLTRB(10, 5, 0, 0),
child: Hero(
tag: photoList![index].thumbnail,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ImagePage(
photoList[index]
.thumbnail
.toString())));
},
child: Stack(fit: StackFit.expand,
children: [
Image.file(
fit: BoxFit.cover,
File(photoList[index].thumbnail.toString()),
),
Positioned(
right: 3,
bottom: 3,
child: Column(crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${DateFormat('Hm', 'en_US').format(DateTime.fromMillisecondsSinceEpoch(photoList[index].id))}',
style: const TextStyle(
color: Colors.white,
fontSize: 9,
fontWeight: FontWeight.bold),
),
Text(
'${DateFormat('dd/MM/yyyy').format(DateTime.fromMillisecondsSinceEpoch(photoList[index].millisecond))}',
style: TextStyle(
color: Colors.white,
fontSize: 9,
fontWeight: FontWeight.bold),
), ],),),],),),),);}, );
} else {
return const Center(
child: CircularProgressIndicator(
color: Colors.blue,
),
);
}
},
),
I am creating my gallery using gridview builder.Thumbnail is photo name.I am generating date data using milliseconds.I want to show photos taken on the same day as a group.I can find the changed date using for loop.i don't know how to do this.
I'm having this "extra space" on my first listview item that is a card being encapsulated in a container.
How do I remove it?
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(15.0),
height: 300,
child: Column(children: [
Row(children: [
Expanded(
child: Text("Lowest Fuel Price",
style: TextStyle(
fontWeight: FontWeight.w500,
color: Theme.orange3,
fontSize: 16.0)))
]),
Container(
height: 250,
child: Card(
elevation: 3,
child: ListView.builder(
itemCount: cheapest.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final item = cheapest[index];
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(
item.petrolType,
style: TextStyle(
color: Theme.gray1, fontSize: 18),
),
Text(
"\$" + item.petrolPrice,
style: TextStyle(
color: Theme.gray1, fontSize: 25),
),
Image(
fit: BoxFit.fill,
image: new AssetImage(
'assets/images/fuel_station/' +
item.petrolStation.toLowerCase() +
'.png')),
]),
index != cheapest.length - 1
? Divider(
color: Colors.grey,
)
: Divider(color: Colors.white)
],
);
})),
)
]));
}
https://api.flutter.dev/flutter/widgets/ListView-class.html
By default, ListView will automatically pad the list's scrollable extremities to avoid partial obstructions indicated by MediaQuery's padding. To avoid this behaviour, override with a zero-padding property.
Card(
elevation: 3,
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView.builder(),
),
),
In the code below, I am trying to pass data from the home screen to the detail screen when user clicks on any of the product listed on the home screen. I seem to be having difficulty here.
Similar Question but does not solve my issue
Excerpt of the code at the home screen.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("name")
.limit(12)
.orderBy("Published Date", descending: true)
.snapshots(),
builder: (context, snapshot){
if (!snapshot.hasData) {
return Center(
child: spinkit,
);
}
return GridView.builder(
physics: ScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10,
),
itemBuilder: (BuildContext context, int index){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: spinkit,
);
}
print("${snapshot.data.documents[index].get('Product Title')}");
return GestureDetector(
onTap: (){
// ===> SEND USER TO THE DETAILS SCREEN <===
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductDetailsScreen()),
);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Stack(
children: [
Container(
height: 150,
width: 150,
child: Image.network(
snapshot.data.documents[index].get('image') ?? spinkit,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
Positioned(
left: 0,
bottom: 0,
child: Container(
height: 20,
width: 150,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black38,
Colors.black38,
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
)),
),
),
Positioned(
left: 4,
bottom: 5,
child: Text(
snapshot.data.documents[index].get('name') ?? "Product Name",
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Palette.whiteColor,
fontSize: 11,
fontWeight: FontWeight.bold),
),
)
],
),
),
);
}
);
},
)
And excerpt of the code at the Details Screen. what you see at the detail screen is data that I have populated manually. it is not coming from firestore.
class ProductDetailsScreen extends StatefulWidget {
#override
_ProductDetailsScreenState createState() => _ProductDetailsScreenState();
}
class _ProductDetailsScreenState extends State<ProductDetailsScreen> {
final productDb = FirebaseFirestore.instance.collection("name");
User user = FirebaseAuth.instance.currentUser;
final spinkit = SpinKitHourGlass(
color: Colors.white,
size: 50.0,
);
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onBackPressed,
child: Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.only(left: 15, right: 15, top: 3, bottom: 10),
child: FutureBuilder(
future: productDb.get(),
builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: spinkit,
);
}
return Container(
child: ListView(
children: [
Column(
children: [
Center(
child: Container(
width: 350,
child: Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(8),
child: Container(
height: 220,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage("asset/images/headphone.jpg",)
)
),
),
),
),
),
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Item Name",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
Text("Item Price",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
],
),
SizedBox(height: 10,),
Text("Item Description",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
Container(
height: 1,
width: 100,
color: Colors.black12,
),
SizedBox(height: 10,),
Container(
height: 140,
width: 350,
child: SingleChildScrollView(
child: Wrap(
children: [
Text(
"What is Lorem Ipsum Lorem Ipsum is simply dummy "
"text of the printing and typesetting industry"
" Lorem Ipsum has been the industry's standard"
" dummy text ever since the 1500s when an "
"unknown printer took a galley of type and "
"scrambled it to make a type specimen book "
"it has?",
textAlign: TextAlign.justify,
style: TextStyle(
color: Palette.blackColor,
fontSize: 16,
),),
]
),
),
),
],
),
],
),
);
},
),
)),
),
);
}
}
In your GestureDetector onTap
// ===> SEND USER TO THE DETAILS SCREEN WITH DOC<===
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductDetailsScreen(snapshot.data.documents[index])),
);
Then
class ProductDetailsScreen extends StatefulWidget {
ProductDetailsScreen(this.doc);
QueryDocumentSnapshot doc;
#override
_ProductDetailsScreenState createState() => _ProductDetailsScreenState();
}
Access in _ProductDetailsScreenState as widget.doc.
The document data will be found at widget.doc.data as a Map<String, dynamic>.
I am very much new to flutter. This is my first time using providers. I have been through every solution out there but nothing seems to help.
In a shopping app I am developing, I tried to use the provider package to pass data to my widget dynamically.
I am sharing the code and the screenshot of the very big error message. Hope somebody could help
Gridview builder
final productData = Provider.of<ProductsProvider>(context);
final products = productData.items;
return GridView.builder(
padding: EdgeInsets.all(10),
itemCount: products.length,
itemBuilder: (context, index) => ChangeNotifierProvider.value(
value: products[index], child: ProductItem()),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.75,
crossAxisSpacing: 10,
mainAxisSpacing: 10),
);
Individual product item in the grid
final product = Provider.of<Product>(context);
return Container(
child: GestureDetector(
onTap: () {
Navigator.of(context)
.pushNamed(ProductDetails.routeName, arguments: product.id);
},
child: Card(
color: Colors.white,
elevation: 6,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//product image
Image(image: AssetImage(product.imageUrl)),
Padding(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 10),
//item name and fav button
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
child: Text(
product.name,
style: Theme.of(context)
.textTheme
.headline1
.copyWith(fontSize: 16, color: Colors.black),
)),
IconButton(
icon: Icon(
product.isFav
? Icons.favorite
: Icons.favorite_border,
color: Colors.red,
),
onPressed: () {
product.toggleFav();
})
],
),
),
// price and buy button
Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
child: Text(
"\$ " + product.price.toString(),
style: Theme.of(context).textTheme.headline1.copyWith(
color: Theme.of(context).primaryColor, fontSize: 15),
)),
SizedBox(
width: 60,
child: RaisedButton(
onPressed: () {},
color: Colors.orange,
child: Text(
"Buy",
style: TextStyle(fontFamily: 'Prompt', fontSize: 14),
),
),
)
],
),
),
],
),
),
),
);
screenshot of error
You need to declare the provider in you main material widget. Atm you are using it but you haven't told flutter that you will use it.
https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifierprovider