I will explain with simple examble,
class Demo1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
Flexible(
child: ListView(
shrinkWrap: true,
children: const [
ListTile(
leading: Icon(Icons.image),
title: Text('with shrinkwrap is true'),
trailing: Icon(Icons.delete_forever),
),
])),
Expanded(
child: Container(
color: Colors.green,
)),
],
),
),
);
}
}
Here the green colored container is not filling the remaining space, so how to fill the remaining area?
Thanks in advance
Try below code and just Remove your first Flexible Widget
Column(
children: <Widget>[
ListView(
shrinkWrap: true,
children: const [
ListTile(
leading: Icon(Icons.image),
title: Text('with shrinkwrap is true'),
trailing: Icon(Icons.delete_forever),
),
],
),
Expanded(
child: Container(
color: Colors.green,
),
),
],
),
You can use SingleChildScrollView instead of using ListView with shrinkWrap: true.
class Demo1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
SingleChildScrollView(
child: Column(
children: const [
ListTile(
leading: Icon(Icons.image),
title: Text('with shrinkwrap is true'),
trailing: Icon(Icons.delete_forever),
),
],
),
),
Expanded(
child: Container(
color: Colors.green,
)),
],
),
),
);
}
}
You may also like CustomScrollView over SingleChildScrollView and shrinkWrap:true.
Both Flexible and Expanded have flex value 1, so they both request 50% of the available space. So the Container child of Expanded takes fills only half space, while the ListView, a child of Flexible, also requests half the space but needs very little space.
You can make Container fill the available space by removing Flexible, so Expanded that wraps Container will get all the available space.
Related
I have an issue with the whole screen scrolling in Flutter. Only the Expanded widget is able to scroll on-screen in my app but I want to make the whole screen scrollable. How can I do that? Here is my code e.g.
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
'My App',
style: AppTheme.of(context).title1,
),
elevation: 0,
backgroundColor: Colors.amber,
),
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(10, 20, 10, 0),
child: Column(
. // Padding repeats two more times
.
.
.
Expanded(
child: MyWidget(
myProp1: value1,
myProp2: value2,
myProp3: value3,
myProp4: value4,
myProp5: value5,
myProp6: value6
) // MyWidget
), // Expanded
],
), // Column
); // Scaffold
}
I've tried to wrap Column with SingleChildScrollview widget but it didn't work for me. I guess I can not use Expanded widget in SingleChildScrollview. I also tried to use Container or etc. instead of Expanded and Column widgets but I couldn't solve this issue. Can anybody help me with it?
There is no need to wrap MyWidget with Expanded. Just Change Column into ListView:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
'My App',
),
elevation: 0,
backgroundColor: Colors.amber,
),
body: ListView(
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(10, 20, 10, 0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
decoration: BoxDecoration(color: Colors.black),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
decoration: BoxDecoration(color: Colors.black),
),
)
],
))
],
), // Column
); // Scaffold
}
You also can use the SingleChildScroll view as Child of Expanded widget will work fine
I need a global area on top to show some ads. This are remains the same for all pages and widgets. So far I've got this:
Stack(
children: [
Column(
children: <Widget>[
Container(
color: Theme.of(context).primaryColor,
width: double.infinity,
height: bannerHeight,
child: MY_BANNER,
),
Expanded(child: child!), // this has to be dynamic
],
),
],
);
What's the problem? It creates an extra padding for the AppBar that I don't know how to remove:
Instead of creating a space on top of AppBar you can put your banner ads below it. For this you can make a custom MyAppBar widget and use this custom widget inside the Scaffold.
class MyAppBar extends StatelessWidget with PreferredSizeWidget {
final String title;
MyAppBar(this.title) : preferredSize = const Size.fromHeight(110);
#override
final Size preferredSize;
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.max,
children: [
AppBar(
title: Text(
title,
),
),
Center(
child: Container( // Place your ad here
color: Colors.red,
width: MediaQuery.of(context).size.width / 2,
height: 50,
),
),
],
);
}
}
and use it like
Scaffold(
appBar: MyAppBar(
"Hello App",
),
),
return Scaffold(
body: SafeArea(
child: Column(
children: [
Row(
children: [
Expanded(
child: MY_BANNER
),
],
),
Expanded(child: child!),
],
),
),
);
I am a new flutter developer.I try to make listview to view a set of data that comes from the database.The list now works, but as follows:
Now it is not presented separately.I need to display every element in the card.An example of what I'm trying to do:
In this picture, each item on the card is separate and separated from the second.How I can do it?If anyone knows the solution please help me.
my code now like that:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: Card(
child :FutureBuilder<List<Flowerdata>>(
future: fetchFlowers(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Center(
child: CircularProgressIndicator()
);
return ListView(
children: snapshot.data
.map((data) => Column(children: <Widget>[
GestureDetector(
onTap: ()=>{
getItemAndNavigate(data.id, context)
},
child: Row(
children: [
Container(
width: 100,
height: 100,
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child:
Image.network(data.flowerImageURL,
width: 200, height: 100, fit: BoxFit.cover,))),
Flexible(child:
Text(data.flowerName,
style: TextStyle(fontSize: 18))
),
]),),
Divider(color: Colors.black),
],
))
.toList(),
);
},
)
),
),
]
)
);
}
You need to wrap your item's Column(not the FutureBuilder) in with Card
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
Expanded(
child: FutureBuilder<List<Flowerdata>>(
future: fetchFlowers(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
return ListView(
children: snapshot.data
.map((data) => Card(
child: Column(
children: <Widget>[
GestureDetector(
onTap: () => {getItemAndNavigate(data.id, context)},
child: Row(children: [
Container(
width: 100,
height: 100,
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(
data.flowerImageURL,
width: 200,
height: 100,
fit: BoxFit.cover,
))),
Flexible(
child: Text(data.flowerName,
style: TextStyle(fontSize: 18))),
]),
),
Divider(color: Colors.black),
],
),
))
.toList(),
);
},
),
),
]));
}
Setup
Start a new Flutter project. I'm calling mine flutter_listview.
Open main.dart and replace the code with the following:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ListViews',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: Scaffold(
appBar: AppBar(title: Text('ListViews')),
body: BodyLayout(),
),
);
}
}
class BodyLayout extends StatelessWidget {
#override
Widget build(BuildContext context) {
return _myListView(context);
}
}
// replace this function with the code in the examples
Widget _myListView(BuildContext context) {
return ListView();
}
Note the _myListView() function at the end. You will be replacing this with the code in the examples below
Basic types of ListViews
Static ListView
If you have a short list of items that don't change, then you can use the default ListView constructor to make it. This is useful for making something like a settings menu page.
Replace _myListView() with the following:
Widget _myListView(BuildContext context) {
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
Run the app and you should see the following image. (After this when refreshing, usually hot reload works fine, but I find at times I need to do a hot restart or even completely stop and restart the app.)
ListTile customization
The Flutter team designed the ListTile widget to handle the normal content that you would want in a list. This means that most of the time there is no need to define a custom layout. You can just use the default ListTile for each item in the list. When we made a ListView in the example above we only used the title option. But we can also show subtitles, images, and icons.
Replace _myListView() with the following
Widget _myListView(BuildContext context) {
return ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.wb_sunny),
title: Text('Sun'),
),
ListTile(
leading: Icon(Icons.brightness_3),
title: Text('Moon'),
),
ListTile(
leading: Icon(Icons.star),
title: Text('Star'),
),
],
);
}
The leading is for adding an icon or image at the start of the ListTile.
You can also add an icon at the end if you specify the trailing attribute.
ListTile(
leading: Icon(Icons.wb_sunny),
title: Text('Sun'),
trailing: Icon(Icons.keyboard_arrow_right),
)
The right arrow icon makes it look like the list items are clickable, but they aren't. Not yet. We will see how to add touch events in the next section. It's easy. (Hint: onTap )
Instead of icons, we can also use images. The recommended image option is to use a CircleAvatar widget.
Replace _myListView() with the following:
Widget _myListView(BuildContext context) {
return ListView(
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/sun.jpg'),
),
title: Text('Sun'),
),
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/moon.jpg'),
),
title: Text('Moon'),
),
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/stars.jpg'),
),
title: Text('Star'),
),
],
);
}
If you want MASTERING FLUTTER LISTVIEWS enter link description here
I'm trying to display an ad using the admob_flutter package: https://pub.dev/packages/admob_flutter, which basically allows me to display the ad just like any other widget.
Following the documentation, I added a widget within a column layout as below (relevant code only):
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(fileName),
backgroundColor: Colors.teal,
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: (){
},
),
],
),
body: Container(
padding: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
TextField(
...
),
AdmobBanner(
adUnitId: 'ca-app-pub-39402560999XXXXXX/XXXXXXXXX',
adSize: AdmobBannerSize.BANNER,
),
],
),
),
bottomNavigationBar: BottomAppBar(...)
As per documentation, this is all I have to do, but I get an overflow error as seen in screenshot below:
I tried wrapping these in Expanded() and Flexible() but that did not fix my problem?
What am I doing wrong here?
You should wrap your Widgets in a Scrollable Widget so they can be scrolled when the contents exceeds the device screen's size.
I wrapped your widgets in a SingleChildScrollView, check the demo below:
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(fileName),
backgroundColor: Colors.teal,
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: (){
},
),
],
),
body: SingleChildScrollView( // new line
child: Container(
padding: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
TextField(
...
),
AdmobBanner(
adUnitId: 'ca-app-pub-39402560999XXXXXX/XXXXXXXXX',
adSize: AdmobBannerSize.BANNER,
),
],
),
),
)
bottomNavigationBar: BottomAppBar(...)
Just change Column to Listview
You can use ListView , SingleChildScrollView or ListView.builder if you want dynamic contents in place of Column
body: Container(
padding: EdgeInsets.all(5.0),
child: Column(..),),
I'm reseaching now for more hours and don't get why it's not possible to put an image and a card with a bunch of ListTiles in a Row.
The error what im getting is:
The following assertion was thrown during performLayout():
BoxConstraints forces an infinite width.
The offending constraints were:
BoxConstraints(w=Infinity, 0.0<=h<=Infinity)
But i dont really get what exactly has to be in a Box should it be the Card with the ListTiles?
Can someone help me with this?
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child:
/* card == null
? loadCards()
: ListTile() */
SingleChildScrollView(
child: Card(
child: Row(mainAxisSize: MainAxisSize.min, children: [
Image.network(
"widget.card.imageUrl",
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
),
);
},
),
Card(
child: Column(mainAxisSize: MainAxisSize.min, children: [
ListTile(
trailing: Icon(Icons.play_arrow),
title: Text("Black Lotus"),
subtitle: Text("Name"),
),
Container(
child: Row(
children: [Icon(Icons.play_arrow), Icon(Icons.polymer)],
),
),
ListTile(
title: Text("Hello"),
),
ListTile(
title: Text("Hello"),
),
]),
),
]),
),
),
),
);
}
Wrap Card with Expanded/Flexible which will solve your constraint problem, Also it's very important to give image width, as at remaining space you are putting other widgets.
return Scaffold(
appBar: AppBar(
title: Text('Sample'),
),
body: SingleChildScrollView(
child: Card(
child: Row(mainAxisSize: MainAxisSize.min, children: [
Image.network(
"https://cdn.pixabay.com/photo/2018/07/11/21/51/toast-3532016_1280.jpg",
width: 40,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
),
);
},
),
Expanded(
child: Card(
child: Column(mainAxisSize: MainAxisSize.min, children: [
ListTile(
trailing: Icon(Icons.play_arrow),
title: Text("Black Lotus"),
subtitle: Text("Name"),
),
Container(
child: Row(
children: [Icon(Icons.play_arrow), Icon(Icons.polymer)],
),
),
ListTile(
title: Text("Hello"),
),
ListTile(
title: Text("Hello"),
),
]),
),
),
]),
),
),
);
Your ListTile needs constraints so it knows where its bounds are.
Just give it some constraints (eg. by wrapping in a SizedBox with a width) or, if you want to take it as much space as possible, just wrap each ListTile with a Flex widget such as Flexible or Expanded if you want to share space evenly with all tiles on that Column.