Why are the images not sharp? - flutter

I am building a small "MyAnimeList" App in Flutter and I am currently building the Details Page, in which I want to show the "Related Anime".
Because I do not want them to use much space I resize them down (like in the picture) but they are blurry
My Image Code is:
class Thumbnail extends StatelessWidget {
final String url;
final double? width;
final double? height;
const Thumbnail({
super.key,
required this.url,
this.width,
this.height,
});
#override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.network(
fit: BoxFit.fill,
url,
width: width,
height: height,
cacheWidth: width?.toInt(),
cacheHeight: height?.toInt(),
filterQuality: FilterQuality.high,
loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
),
);
},
),
);
}
}
Which I use like this:
Thumbnail(
url: e.node.mainPicture.medium,
width: MediaQuery.of(context).size.width * 0.10,
),
I do not find anything related to this by googling it and tbh, I do not really understand why this happens :(
I appreciate every help!

Related

Flutter how to pass a widget as a parameter

I've been developing a mobile app in flutter for a few days and just to reuse some code I'd like to pass a widget as a parameter so I don't have to duplicate a bunch of code. I tried some solutions I found here but none of them worked.
Here's what I have so far:
CarouselItem.dart
class CarouselItem extends StatelessWidget {
CarouselItem({
Key? key,
required this.index, required this.height, required this.width, required this.title, required this.destination,
}) : super(key: key);
final int index;
final double height;
final double width;
final String title;
final RouteOneCallBack destination; //trying to pass the widget
//List of images
List<String> list = [
'https://audioguia.s3.eu-west-3.amazonaws.com/FOTOS/Alqueva/A1-placa+entrada.jpg',
];
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.all(6.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: GestureDetector(
child: Image.network(
list[index],
fit: BoxFit.cover,
height: height,
width: width,
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
destination(), //widget goes here
),
);
},
),
),
),
SizedBox(height: 20),
Container(
padding: EdgeInsets.only(left: 10),
child: Text(
title,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
],
);
}
}
Home.dart
How I want this to go
items: [
CarouselItem(
index: 0,
width: 500,
height: 200,
title: "Destino 1",
destination: RouteOne()
),
Am I missing an extra step? Thanks in advance.
Basically what I want to do is the same I do with the String or int parameters I already have, but can't seem to understand how to do this with a widget.
RouteOne() is a stateful widget
class BottomSheetDialog extends StatelessWidget {
final Widget? child;
const BottomSheetDialog({Key? key, #required this.child}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: Sizes.s350,
decoration: BoxDecoration(
color: Get.theme.cardColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(Sizes.s30),
topRight: Radius.circular(Sizes.s30))),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(child: child!),
],
));
}
}
// call
BottomSheetDialog(child:const Text("test"));
You can pass the widget as a parameter because the StatefulWidget extends the Widget.
Here is common usage.
final Widget destination;

Retrieve array of images from Firestore - flutter

I am currently trying to retrieve a list of images from Firestore and display them on the screen like this
But I can only retrieve one image from the list. Please help me display all images from Firestore.
How I stream data from Firestore
StreamBuilder<QuerySnapshot>(
stream:
FirebaseFirestore.instance.collection('properties').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text('Fail to load..');
} else if (snapshot.hasData || snapshot.data != null) {
return ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount:
snapshot.data?.docs.length,
itemBuilder: (BuildContext context, int index) {
QueryDocumentSnapshot<Object?>? documentSnapshot =
snapshot.data!.docs[index];
return TestPropertyCard(itemData: documentSnapshot);
});
}
return Container();
},
),
Property Card
class TestPropertyCard extends StatelessWidget {
final dynamic itemData;
const TestPropertyCard({Key? key, required this.itemData}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => PropertyDetailPage(
itemData: itemData,
)));
},
child: Container(
height: 200,
margin: const EdgeInsets.only(bottom: 8, left: 5, right: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7),
color: NayyaaColorTheme.nayyaaBlue),
child: Column(
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10), topRight: Radius.circular(10)),
child: Image.network(
itemData["CoverPhoto"],
height: 130,
width: MediaQuery.of(context).size.width,
fit: BoxFit.fitWidth,
),
),
When user tap on the property card, the app would the user take to the detail page. On this detail page, I would like to display a list of images that is stored in Firestore as array. See my firestore data structure here.
However, my problem is I can only retrieve one image. Here is my code for detail page
class PropertyDetailPage extends StatelessWidget {
final dynamic itemData;
const PropertyDetailPage({Key? key, required this.itemData}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: [
Image.network(
itemData['Gallery'][0],
fit: BoxFit.fill,
),
],
),
),
);
}
}
I have tried with ListView.builder(). But I couldn't make it work. Thanks in advance.
Looking into the code you are using, it seems fine. It just lacks the mapping from an image url to image widget.
Replace the children in the ListView as below:
children: (itemData['Gallery'] as List).map((imageUrl){
return Image.network(
imageUrl as String,
fit: BoxFit.fill,
);
}).toList(),
it should work assuming the itemData['Gallery'] is a List<String> stored in the firestore

how to pass listView.builder index to a parameter of custom widget in flutter

I want to create a custom widget which will take listview.builder and return a list of items but I am not able to pass the index to paramater of custom widget when I am accessing it in another dart file it throws 'index' not defined.
this is my listView.builder and i am tyring to pass products[index]['name'] to ProductContainer(products[index]['name']) like this... but it throws index not defined error plz help
import 'package:flutter/material.dart';
class ProductContainer extends StatefulWidget {
final String image;
final String name;
final String price;
final String tag;
final Text text;
final double height;
final double width;
ProductContainer({
Key key,
this.image,
this.name,
this.price,
this.tag,
this.text,
this.height,
this.width,
}) : super(key: key);
#override
_ProductContainerState createState() => _ProductContainerState();
}
class _ProductContainerState extends State<ProductContainer> {
var products = [
{
"price": " 100",
"imageLink": "images/fs.jpg",
"tag": "one",
"name": "prod1",
"category": "combo",
}];
#override
Widget build(BuildContext context) {
return SizedBox(
height: 150,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: products.length,
itemBuilder: (context, index) {
return Column(
children: [
forProducts(
height: 120,
width: 120,
image: image ?? image[index]['imageLink'],
tag: products[index]['tag'],
name: products[index]['name'],
category: products[index]["category"],
price: products[index]["price"],
context: context),
],
);
},
),
);
}
}
Widget forProducts(
{String image = "images/",
#required String tag,
#required String name,
#required String category,
#required String price,
#required double height,
#required double width,
#required BuildContext context}) {
return Column(children: [
Material(
child: Hero(
tag: tag,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InfoPage(
image: image,
tag: tag,
name: name,
category: category,
price: price,
)));
},
child: Container(
padding: EdgeInsets.all(2),
margin: EdgeInsets.all(5),
height: 120,
width: 120,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
fit: BoxFit.cover, image: AssetImage(image)),
),
),
))),
Expanded(child: Text(name)),
]);
}
this worked for me, the mistake I did was I had not defined my List products in the dart file wherever I was using this ProductContainer Widget and also it wont take index unless passed as proper instance member with it so it should be like widget.products[index] and not like products[index] as products isnt defined in wherever you will be using your widget. Below is the proper working code.
import 'package:my_Ecomm/screens/info_page.dart';
import 'package:flutter/material.dart';
class ProductContainer extends StatefulWidget {
final List products;
final double height;
final double width;
//final dynamic index; // you can use it like this also to pass index
const ProductContainer({
Key key,
this.products,
this.height,
//this.index,
this.width,
}) : super(key: key);
#override
_ProductContainerState createState() => _ProductContainerState();
}
class _ProductContainerState extends State<ProductContainer> {
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: widget.height + 45,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: widget.products.length,
itemBuilder: (context, index) {
return forProducts(
height: widget.height,
width: widget.width,
image: widget.products[index]['imageLink'],
tag: widget.products[index]['tag'],
name: widget.products[index]['name'],
category: widget.products[index]["category"],
price: widget.products[index]["price"],
context: context);
},
),
),
],
);
}
}
Widget forProducts(
{String image = "images/",
#required String tag,
#required String name,
#required String category,
#required String price,
#required double height,
#required double width,
#required BuildContext context}) {
return Column(children: [
Material(
child: Hero(
tag: tag,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InfoPage(
image: image,
tag: tag,
name: name,
category: category,
price: price,
)));
},
child: Container(
padding: EdgeInsets.all(2),
margin: EdgeInsets.all(5),
height: height,
width: width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
fit: BoxFit.cover, image: AssetImage(image)),
),
),
))),
Expanded(child: Text(name)),
]);
}

how to assign height and width of widget child(container) from another custom widget in flutter

I want to change my width and height of container widget which is inside custom widget forProducts and I want to pass that width and height from another custom ProductContainer widget but when I pass it in ProductContainer it gives undefined name height and width.
here is my code for this
your help is appreciated,
thank you,
import 'package:myEcomm/screens/info_page.dart';
import 'package:flutter/material.dart';
class ProductContainer extends StatefulWidget {
final List products;
final double height;
final double width;
const ProductContainer({
Key key,
this.products,
this.height,
this.width,
}) : super(key: key);
#override
_ProductContainerState createState() => _ProductContainerState();
}
class _ProductContainerState extends State<ProductContainer> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 150,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: widget.products.length,
itemBuilder: (context, index) {
return forProducts(
image: widget.products[index]['imageLink'],
tag: widget.products[index]['tag'],
name: widget.products[index]['name'],
category: widget.products[index]["category"],
price: widget.products[index]["price"],
context: context);
},
),
),
],
),
);
}
}
Widget forProducts(
{String image = "images/",
#required String tag,
#required String name,
#required String category,
#required String price,
#required BuildContext context}) {
return Column(children: [
Material(
child: Hero(
tag: tag,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InfoPage(
image: image,
tag: tag,
name: name,
category: category,
price: price,
)));
},
child: Container(
padding: EdgeInsets.all(2),
margin: EdgeInsets.all(5),
height:
height, // this is the height which I want to assign from productcontainer(height: anyValue) widget
width:
width, // this is the width which I want to assign from productcontainer(width: anyValue) widget
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
fit: BoxFit.cover, image: AssetImage(image)),
),
),
))),
Text(name),
]);
}
This worked for me
import 'package:myEcomm/screens/info_page.dart';
import 'package:flutter/material.dart';
class ProductContainer extends StatefulWidget {
final List products;
final double height;
final double width;
const ProductContainer({
Key key,
this.products,
this.height,
this.width,
}) : super(key: key);
#override
_ProductContainerState createState() => _ProductContainerState();
}
class _ProductContainerState extends State<ProductContainer> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 150,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: widget.products.length,
itemBuilder: (context, index) {
return forProducts(
height: widget.height,
width: widget.width,
image: widget.products[index]['imageLink'],
tag: widget.products[index]['tag'],
name: widget.products[index]['name'],
category: widget.products[index]["category"],
price: widget.products[index]["price"],
context: context);
},
),
),
],
),
);
}
}
Widget forProducts(
{String image = "images/",
#required String tag,
#required String name,
#required String category,
#required String price,
#required double height,
#required double width,
#required BuildContext context}) {
return Column(children: [
Material(
child: Hero(
tag: tag,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InfoPage(
image: image,
tag: tag,
name: name,
category: category,
price: price,
)));
},
child: Container(
padding: EdgeInsets.all(2),
margin: EdgeInsets.all(5),
height: height,
width: width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
fit: BoxFit.cover, image: AssetImage(image)),
),
),
))),
Text(name),
]);
}

Flutter Web sliver: customscrollview

I'm making a flutter web.
I want to resize a horizontal image in a CustomScrollView.
Ex: On a product detail page, I want to place the top image size 600x400 width in the center of the layout.
Regardless of the image size, it is a problem that it expands to 900x or more horizontally.
layout:
code:
class ServiceProductDetailPage extends StatelessWidget {
final String productId;
final ServiceProductModel product;
ServiceProductDetailPage({required this.product, required this.productId});
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
expandedHeight: 50,
title: Text('Title'),
stretch: true,
backgroundColor: Colors.black,
),
SliverToBoxAdapter(child: _Body(context, _product)),
],
),
);
}
}
Widget _Body(BuildContext context, ServiceProductModel product) {
return Card(
child: ConstrainedBox(
constraints: BoxConstraints.tight(Size(900,400)
),
child: LoadingImage(url: product.image),
),
);
}
class LoadingImage extends StatelessWidget {
const LoadingImage({
Key? key,
required this.url,
}) : super(key: key);
final String url;
#override
Widget build(BuildContext context) {
return Image.network(
url,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
errorBuilder: (BuildContext c, Object err, StackTrace? stack) {
return const Center(child: Text('error'));},
frameBuilder: (BuildContext c, Widget image, int? frame, bool sync){
if (!sync && frame == null) {
return const Center(child: CircularProgressIndicator());
}
return image;
},
);
}
}
What you are looking for is an UnconstrainedBox. As per the documentation, the UnconstrainedBox makes itself take the full width of it's parent, but it allows it's child to be of any width the child decides.
So, you can use it like this.
Widget _Body(BuildContext context, ServiceProductModel product) {
return Card(
child: UnconstrainedBox(
child: Container(
color: Colors.deepOrange,
width: 900,
height: 400,
child: LoadingImage(url: product.image),
),
),
);
}
Next, you given some properties to you Image.network that is making it expand.
So remove the following
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
And just add this
fit: BoxFit.contain,
I have given your 900 width Container a color to see that it stays at 900 despite the window being larger than 900.