How to make responsive images in flutter? - flutter

I am using Gridview.builder to make a grid of cards. I didn't find any attribute inside Gridview.builder to decide the size of a single card also inside the Card widget I didn't find any attribute to decide the size of the card.
Further to that, I want to make the image and a text inside the card responsive, here is the code of the method which returns me the card -
Card myCard(String houseName, String houseImageUrl) {
return new Card(
elevation: 5.0,
child: new InkWell(
child: new Container(
alignment: Alignment.center,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Image.network(
houseImageUrl,
height: 180.0,
width: 180.0,
),
new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Text(
houseName,
style: new TextStyle(fontSize: 16.0),
textAlign: TextAlign.center,
),
),
),
],
),
),
));
I have used Gridview.builder as follows ("data" is the data coming from API)
new GridView.builder(
itemCount: data == null ? 0 : data.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemBuilder: (BuildContext context, int index) {
var housename = data.keys.toList()[index].toString();
return myCard(
housename, data[housename]['image'].toString());
})));
The output of this code shows cards like this
Screenshot of above code output

You can use the fit property.
new Image.network(
houseImageUrl,
fit: BoxFit.contain,
height: 180.0,
width: 180.0,
),
The propertyfit: BoxFit.containwill limit the whole image to defined height.

For the Card Size you can use the childAspectRatio attribute inside gridDelegate as follows ->
new GridView.builder(
itemCount: data == null ? 0 : data.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: (1 / 1),
crossAxisCount: 2),
itemBuilder: (BuildContext context, int index) {
var housename = data.keys.toList()[index]
.toString();
return myCard(
housename, data[housename]['image'].toString());
}
)
In above code 1/1 indicates that your cards will have the square shape
further, for image responsiveness, you can use a fit property as #ap14, The code will be like ->
Card myCard(String charName, String charImageUrl) {
return new Card(
elevation: 5.0,
child: new InkWell(
child: new Container(
alignment: Alignment.center,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Padding(
padding:const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
child: new Image.network(
charImageUrl,
fit: BoxFit.contain,
height: 150.0,
width: 150.0,
),
),
new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Text(
charName,
style: new TextStyle(fontSize: 16.0),
textAlign: TextAlign.center,
),
),
),
],
),
),
)
);
}

use ResponsiveGridList from the responsive_grid package
you only specify your desired width and it chooses how many image to fit in a row, you can also set squareCells to true so that images will be forced to layout equal width and height

Related

Flutter, fill the entire screen

I am designing an application and I have realized that in different mobiles the screen occupies different dimensions, I would like the size to be proportional to the size of the mobile, so that it always occupies the entire screen without the need to scroll.
I'd like that the Screen A could be look like the Screen B no matter of the size of the device.
But I have no idea how to do that, this is my code. I also noticed that because of cards I can't scrolling even having a ListView this is not a problem once they get the same size, because then there wont be reason to scroll through
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
centerTitle: true,
title: Text('Gestion de flota'),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.exit_to_app,
),
onPressed: () async {
_signOut().whenComplete(() =>
navigatorKey.currentState.pushReplacementNamed('/login'));
},
)
],
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Form(
key: _formKey,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
SizedBox(
height: 20,
),
GridView.count(
childAspectRatio: (10 / 4),
crossAxisCount: 2,
shrinkWrap: true,
children: [
_getHourStart(),
_getHourEnd(),
_getDateStart(),
_getDateEnd(),
],
),
],
),
SizedBox(height: 10),
Column(
children: <Widget>[
GridView.count(
childAspectRatio: (3 / 0.7),
crossAxisCount: 1,
shrinkWrap: true,
children: [
_getHourStart(),
],
),
],
),
SizedBox(height: 10),
GridView.count(
crossAxisCount: 2,
childAspectRatio: (3 / 2),
shrinkWrap: true,
children: [
Card(
child: _uploadPic(Foto.primera, picList[0]),
),
Card(
child: _uploadPic(Foto.segunda, picList[1]),
),
Card(
child: _uploadPic(Foto.tercera, picList[2]),
),
Card(
child: _uploadPic(Foto.cuarta, picList[3]),
),
],
),
SizedBox(height: 20),
InkWell(
onTap: () async { // more code... }
child: SubmitButton(context, 'Enviar datos'),
),
Container(
padding: EdgeInsets.symmetric(vertical: 10),
alignment: Alignment.centerRight,
),
SizedBox(height: height * .14),
],
),
),
),
);
}
}
you can use MediaQuery
you retrieve the size of mobile screen by:
final height = MediaQuery.of(context).size.height
final width = MediaQuery.of(context).size.width
One solution to this problem is to add Expanded to all the children in the Column widget.
Another and preferable one is :
make your Container height the height of your screen.
body: Container(
height:MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
next add the mainAxisAlignment property to both Column widgets.
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
]

ListView inside a Row with dynamic width

I want to create a ListView and a Button to add items to the ListView.
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Conversation conversation = teamMembers[index];
return SizedBox(
width: 42,
height: 42,
child: Avatar(
name: member.name,
profileUrl: member.profileUrl,
radius: 38,
),
);
},
itemCount: teamMembers.length,
),
),
InkWell(
onTap: () {
_showSheet();
},
child: Container(
width: 42,
height: 42,
decoration: new BoxDecoration(
color: Color(0xfff2f2f2),
borderRadius: BorderRadius.circular(28)),
child: Icon(Icons.add),
),
),
],
)
I'm getting the results as below for lesser number of items and more number of items. How can I make the + button closer to the ListView even if the list length is less.
List<Widget> _buttons = [];
Wrap(
spacing: 12.0, // horiz
runSpacing: 12.0, // vert
crossAxisAlignment: WrapCrossAlignment.start,
alignment: WrapAlignment.start,
children: _buttons,
),
The solution to this issue is replacing the Expanded widget with Flexible widget.
Expanded actually is just a shorthand for Flexible. Flexible takes only the needed space, and Expanded takes all available space, respecting the flex factor.
Flexible with fit: FlexFit.loose which is the default one solves the problem. If the fit is FlexFit.loose, the child can be at most as large as the available space (but is allowed to be smaller)
So,
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Conversation conversation = teamMembers[index];
return SizedBox(
width: 42,
height: 42,
child: Avatar(
name: member.name,
profileUrl: member.profileUrl,
radius: 38,
),
);
},
itemCount: teamMembers.length,
),
),
InkWell(
onTap: () {
_showSheet();
},
child: Container(
width: 42,
height: 42,
decoration: new BoxDecoration(
color: Color(0xfff2f2f2),
borderRadius: BorderRadius.circular(28)),
child: Icon(Icons.add),
),
),
],
)
is the solution.

How to make a bottom sheet with height follow the amount of item of JSON

BottomSheet in Flutter so that the height follows the number of items (data from JSON) is that what? Because I made the height not follow the amount of data but followed 1/2 the screen of each cellphone. So if the phone is long, there is empty space at the bottom. If the cellphone is short, the data is cut by the screen below.
This is the code for creating bottom sheet:
void _showModalBottomSheet(AsyncSnapshot<CatlistResult> snapshot) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return Card(
elevation: 3.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15))),
child: Container(
padding: EdgeInsets.only(left: 16.0, top: 10.0, right: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 10.0),
child: Image.asset('assets/images/main/more_2lines_20dp.png', scale: 3.5),
),
Expanded(
child: GridView.builder(
physics: NeverScrollableScrollPhysics(), //kill scrollable
shrinkWrap: true,
itemCount: snapshot == null ? 0 : snapshot.data.catlist.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4),
itemBuilder: (BuildContext context, int index) {
var numItems = snapshot.data.catlist[index];
if (numItems.f == 1) {
if (numItems.b == 0) {
return GestureDetector(
child: Card(
elevation: 0.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Image.asset('assets/images/main/cat_${numItems.a}.png', fit: BoxFit.cover, width: 50.0, height: 50.0),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Text(
numItems.c,
maxLines: 2,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 10),
),
),
],
),
),
);
}
}
},
),
),
],
),
),
);
}
);
}
And this is the result of my code:
Run from iOS Emulator
Run from Android Emulator
Problems:
In your parent Column you are using
mainAxisSize: MainAxisSize.max
You are also using Expanded in this Column which creates the empty space if there are less items in the GridView. Remove this Expanded widget.
Solution:
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min, // 1st use min not max
children: <Widget>[
Container(...),
GridView.builder(...), // 2nd remove Expanded
],
)

Flutter GridView is not scrolling

I am adding a header in the grid view. The header is scrolling but when touching grid view. It is not scrolling. I want to scroll header and gridview.
I have used SingleChildScrollView and Expanded. How to solve the please help me.
My code is shown below
Widget ItemGridview() {
return Container(
color: Colors.white,
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Expanded(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
new Text(
'Items of products',
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0),
textAlign: TextAlign.left,
),
GridView.count(
shrinkWrap: true,
primary: true,
padding: EdgeInsets.only(top:15.0),
crossAxisCount: 3,
childAspectRatio: 0.60, //1.0
mainAxisSpacing: 0.2, //1.0
crossAxisSpacing: 4.0, //1.0
children: createCategoryList(),
),
],
),
)
)
]
),
);
}
In my code Items of products is the header.
List<Widget> createCategoryList() {
List<Widget> createCategoryList = List<Widget>();
for (int i = 0; i < documents.length; i++) {
createCategoryList
.add(makeGridCell(documents[i].data['title'], "name", 8,documents[i].data['id']));
}
return createCategoryList;
}
Container makeGridCell(String name, String image, int count, String id) {
return Container(
child: new GestureDetector(
onTap: () {
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
verticalDirection: VerticalDirection.down,
children: <Widget>[
new Container(
child: Image.asset('assets/' + image + ".jpg"),
),
new Container(
color: Colors.white,
padding: EdgeInsets.only(left: 5),
child: new Text(name,
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 18.0)),
),
],
),
));
}
The createCategoryList() is the list of items in grid written in widget.
I had similar widget tree like you
a gridview.count() wrapped in SingleChildScrollView adding
physics: ScrollPhysics(),
to GridView.count() Widget Solved my problem
source:https://github.com/flutter/flutter/issues/19205
Add physics: ScrollPhysics() property to Gridview. it iwll scroll.
just add some property in GridView
Widget _buildFields(BuildContext context) {
return Container(
color: Colors.white,
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: NeverScrollableScrollPhysics(),
children: List.generate(choices.length, (index) {
return Center(
child: new Column(
children: [
new Expanded(
child: SelectCard(choice: choices[index]),//your card wight
),
],
),
);
}),
));
}
and use like this
class _Dashboard extends State<Dashboard> {
#override
Widget build(BuildContext context) {
return OrientationBuilder(builder: (context, orientation) {
return ListView(
children: <Widget>[
Container(
height: 200,
child: Image.network(
"https://www.gizbot.com/img/2013/11/23-weekend-deals-top-10-latest-smartphones.jpg"),
),
_buildFields(context),
],
);
});
}
}
You have some issues related to the Scroll of your widgets, you can reduce the amount of Widgets using Wrap, like this :
Container(
color: Colors.white,
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'Items of products',
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0),
textAlign: TextAlign.left,
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Wrap(
spacing: 20.0,
alignment: WrapAlignment.spaceEvenly,
children:createCategoryList(),
),
],
),
)
)
]
),
);
Add a constraint width or a fixed with to the widget of your item:
return Container(
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width / 4),
child: new GestureDetector(
I think you need to use some custom scroll view
CustomScrollView(
primary: false,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(20.0),
sliver: SliverGrid.count(
crossAxisSpacing: 10.0,
crossAxisCount: 2,
children: <Widget>[
const Text('He\'d have you all unravel at the'),
const Text('Heed not the rabble'),
const Text('Sound of screams but the'),
const Text('Who scream'),
const Text('Revolution is coming...'),
const Text('Revolution, they...'),
],
),
),
],
)
Just ran into this myself, change your primary parameter for the GridView to false, give that a try.
In Gridview.builder scrolling is not working for smaller resolutions like tablet mode,mobile mode then just wrap the Gridview.builder under the listview.builder widget.
SizedBox(
width: screenSize.width,
height: screenSize.height * entry.contentHeightFactor,
child: ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return Card(
child: Container(
width: screenSize.width * 0.8,
height: screenSize.height * 0.72,
padding: const EdgeInsets.all(10),
child: GridView.builder(
scrollDirection: Axis.vertical,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
padding: const EdgeInsets.all(5),
itemCount: 30,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child:Card(....),
);
},
),
),
);
},
),
),

infinity height in the listview of the flutter

Hi friends i am new to the flutter development here i am using the list view please find this image
Where i am want to remove the white space above and below the image make it stretch on this white spaces i am tried to sized box but its given error that double.infinity cant be used please find the below code please help me out friends
new SliverList(
delegate: new SliverChildBuilderDelegate(
(BuildContext context, int index) {
return new GestureDetector(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new News_Details(
postid: latest_news_list[index]['id'],
)));
},
child: new Card(
elevation: 4.0,
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0),
child: new Row(
children: <Widget>[
**new Container(
child: new Image.network(
latest_news_list[index]['image'],
width: 150.0,
fit: BoxFit.cover,
),
),**
new Flexible(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: new Text(latest_news_list[index]['title']),
margin: EdgeInsets.only(left: 10.0, top: 10.0),
),
new Container(
child: new Divider(
color: secondarycolor,
),
margin: EdgeInsets.only(right: 10.0, left: 10.0),
),
new Container(
child: new Text(
latest_news_list[index]['content'],
softWrap: true,
maxLines: 4,
),
margin: EdgeInsets.only(
left: 10.0, top: 5.0, bottom: 5.0),
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Container(
child: new Text('VSB News'),
margin:
EdgeInsets.only(left: 10.0, top: 10.0,bottom: 10.0),
),
new Container(
child: new Text(
latest_news_list[index]['post_dt']),
margin:
EdgeInsets.only(left: 10.0, top: 10.0,right: 10.0,bottom: 10.0),
),
],
)
],
),
)
],
),
),
);
},
childCount: latest_news_list == null ? 0 : latest_news_list.length,
),
),
You can edit the line
fit: BoxFit.cover
to
fit: BoxFit.fitHeight
inside you container that grabs image from network.
I think you are trying to put a list inside another list, so the error shows
you can put the list (nested list which is inside the list) in a container and specify a height :
ListView _buildMainView(){
return new ListView(
children: <Widget>[
new Text("Main List"),
new Container(
height: 100.0,
child: new ListView(
children: <Widget>[
new Text("Nested List")
],
),
)
],
);
)
If you have a ListView with vertical scroll direction, and want it to have a infinity height, maybe you don't need a ListView.
You can use a regular Column.