Related
How can you add more Containers or Widgets after using FutureBuilder?
I've been trying to combine these 2 blocks of code into one but can't figure out how to do so. I need the 2 buttons from code-block 2 to be added after this ListView.builder. Or does this have to be on 2 separate pages?
#override
Widget build(BuildContext context) =>
Scaffold(
body:
FutureBuilder<ListResult>(
future: futureFiles,
builder: (context, snapshot) {
if (snapshot.hasData) {
final files = snapshot.data!.items;
return ListView.builder(
itemCount: files.length,
itemBuilder: (context, index) {
final file = files[index];
double? progress = downloadProgress[index];
return ListTile(
title: Text(file.name),
subtitle: progress != null
? LinearProgressIndicator(
value: progress,
backgroundColor: Colors.black26,
)
: null,
trailing: IconButton(
icon: const Icon(
Icons.download,
color: Colors.white,
),
onPressed: () => downloadFile(index, file),
));
});
} else if (snapshot.hasError) {
return const Center(child: Text('Error occurred'));
} else {
return const Center(child: CircularProgressIndicator());
}
},
)
);
}
I want to combine the following code into the code above. But can't quite figure out how to do that.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if(pickedFile != null)
Expanded(
child: Container(
child: Center(
child: Image.file(File(pickedFile!.path!),width:double.infinity,fit: BoxFit.cover,),
//child: Text(pickedFile!.name),
)
)
),
if (pickedFile == null)
Expanded(
child: Container(
child: Center(
displayFiles()
)
)
),
Row(
mainAxisAlignment : MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: SizedBox(
height:40,
width: 150,
child:
ElevatedButton(
child: Text('Select File'),
onPressed: selectFile,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
textStyle: const TextStyle(fontSize: 20),
),
),
),
),
SizedBox(
height:40,
width: 150,
child: ElevatedButton(
child: Text('Upload File'),
onPressed: uploadFile,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
textStyle: const TextStyle(fontSize: 20)
),
),
),
],
),
buildProgress(),
],
),
),
);
}
I tried wrapping the buttons inside a Container but I can't figure out where to place the Container in the first block of code.
Do like this
Column(
children: [
Expanded(
child: FutureBuilder<ListResult>()),
//Second page code
Center()
]
)
You may return a Column widget from the builder of FutureBuilder instead of returning a ListView, and make ListView the first child of that Column. The buttons can be defined as second, third....etc children as you please.
itemCount: files.length + 3;
final file = files[index+3];
if(index==0){
(some widget)
}
else if(index==1){
(some widget)
}
if(index==2){
(some widget)
}else return ListTile()
I wanted to achieve the following output but instead of one row in a column, I want to show two rows in a column using ListView.separated. How can I get it? ListView.separated does not have any option to display 2 rows.
Scaffold(
body: ListView.separated(
itemBuilder: (context, position) {
return Container(
height: 40.0,
color: Colors.white,
child: Text('Your text goes here'),
);
},
separatorBuilder: (context, position) {
return Container(
color: Colors.red,
child: Text('Divider'),
);
},
itemCount: 20,
),
));
To achieve this, you can use the Row widget. In order to expand the Text widgets, you can wrap them with Expanded.
Full working example, based on your code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView.separated(
itemBuilder: (context, position) {
return Container(
height: 40.0,
color: Colors.white,
child: Text('Your text goes here'),
);
},
separatorBuilder: (context, position) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Text(
'Divider 1',
textAlign: TextAlign.center,
),
),
),
Expanded(
child: Container(
color: Colors.red,
child: Text(
'Divider 2',
textAlign: TextAlign.center,
),
),
),
],
);
},
itemCount: 20,
),
),
);
}
}
I would like to include buttons between AppBar and ListView. In the example below, the buttons scroll along with the text. I tried to include the SingleChildScrollView within a Column, but was unsuccessful.
I read that the Column widget does not support scrolling. I already searched a lot, but I didn't find an example similar to what I need.
Can someone help me?
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('A Idade do Lobo'),
elevation: 0.0,
backgroundColor: COLOR_MAIN,
),
body: NotificationListener(
onNotification: (notif) {
if (_hasScroll) {
if (notif is ScrollEndNotification && scrollOn) {
Timer(Duration(seconds: 1), () {
_scroll();
setState(() {
_controlButton();
});
});
}
}
return true;
},
child: SingleChildScrollView(
controller: _scrollController,
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Center(
child: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new RaisedButton(
onPressed: _showScrollPickerDialog,
child: Text('Rolagem ${_scrollSpeed}'),
),
new RaisedButton(
onPressed: _showTomPickerDialog,
child: Text('TOM ${_tom}'),
),
],
),
),
new Flexible(
fit: FlexFit.loose,
child: new ListView.builder(
shrinkWrap: true,
itemCount: _songDetails.length,
itemBuilder: (context, index) {
return new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: new EdgeInsets.all(5.0),
child: new RichText(
text: TextSpan(children: [
new TextSpan(
text: '${_songDetails[index].line}',
style: _getStyle(
_songDetails[index].type,
),
),
]),
),
),
],
);
},
),
),
],
),
),
),
floatingActionButton: _controlButton(),
);
}
}
You can use bottom properly of AppBar to achieve desire UI.
Following example clear your idea.
import 'package:flutter/material.dart';
class DeleteWidget extends StatefulWidget {
const DeleteWidget({Key key}) : super(key: key);
#override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("your title"),
bottom: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 40),
child: Center(
child: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new RaisedButton(
onPressed: () {},
child: Text('Rolagem '),
),
new RaisedButton(
onPressed: () {},
child: Text('TOM '),
),
],
),
),
),
),
body: Container(
child: ListView.builder(
itemBuilder: (context, int index) {
return Text(index.toString());
},
itemCount: 100,
),
));
}
}
So i have this script which is build a listview
class NewProductsLists extends StatelessWidget {
final List<NewProducts> newlist;
NewProductsLists({Key key, this.newlist}) : super(key: key);
final formatCurrency =
new NumberFormat.simpleCurrency(locale: "id", decimalDigits: 2);
#override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
itemCount: newlist.length,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
print("Product detail");
},
child: Card(
child: Container(
width: MediaQuery.of(context).size.width * 0.50,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.network(
Configuration.url +
"assets/app_assets/" +
newlist[index].productImage,
width: 90,
height: 90,
filterQuality: FilterQuality.low),
ListTile(
title: Center(
child: Text(
newlist[index].productName,
style: TextStyle(fontSize: 18),
)),
subtitle: Center(
child: Text(
formatCurrency.format(
int.parse(newlist[index].productPrice)),
style: TextStyle(color: Colors.red, fontSize: 15),
)),
),
],
)),
),
);
}));
}
}
and the result looks like this
[
As you can see the card is expanding so hard. I know it is because the Expanded widget. Is it possible to make the card wrap_content ?
For horizontal list view needs fixed height if its not going to be vertical scrollable view you can use Expanded widget with varying flex to get it working.
Working build widget by using expanded widget.
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
centerTitle: false,
title: const Text('November'),
),
body: new Container(
child: Column(
children: <Widget>[
new Expanded(flex: 1,child: new Container(color: Colors.grey[300],),),
Expanded(flex: 2,
child: ListView.builder(
itemCount: 10,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
print("Product detail");
},
child: Card(
child: Container(
width: MediaQuery.of(context).size.width * 0.50,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.network(
'https://homepages.cae.wisc.edu/~ece533/images/watch.png',
width: 90,
height: 90,
filterQuality: FilterQuality.low),
ListTile(
title: Center(
child: Text(
'item Name ${index}',
style: TextStyle(fontSize: 18),
)),
subtitle: Center(
child: Text(
'\$10',
style: TextStyle(
color: Colors.red, fontSize: 15),
)),
),
],
)),
),
);
}),
),
new Expanded(flex: 3,child: new Container(color: Colors.amber[100],),),
],
)));
}
Result screen
Let me know if it suits your requirement.
I am developing a Flutter application and I want to dynamically adjust the height of the ListView.
I want the list to have a maximum height of 200. If the height is more than that, user will have to scroll to reach the bottom. If height is below 200, it will take only as much space as needed.
Preview of application: Screenshot. As you can see Restaurants nearby is pushed to the very bottom of the page. I want the ListView to only take height of 200 or less so that the content below isn't pushed to the bottom.
Here is my current code:
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Enter restaurant manually'),
onPressed: () {
print('Button pressed');
},
),
],
),
Flexible(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
);
}
You are using Flexible widget, that's why your ListView expands. You have to change Flexible to ConstrainedBox and add shrinkWrap: true to your ListView.
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200, minHeight: 56.0),
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
More info here: https://api.flutter.dev/flutter/widgets/ConstrainedBox-class.html
You can use LimitedBox
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(...),
Divider(),
Row(...),
LimitedBox(
maxHeight: 200.0,
child: ListView.builder(...),
),
Text(...),
],
),
Recommended solution in case when the incoming constraints are unbounded
Consider wrapping the ListView into this
LimitedBox(
maxHeight: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: _itemsCount,
),
),
]
)
),
Note that:
shrinkWrap of ListView is set to true
mainAxisSize of Column is set to MainAxisSize.min
maxHeight of LimitedBox is set to 200
A complete snippet:
import 'package:flutter/material.dart';
class DebugWidget extends StatefulWidget {
#override
_DebugWidgetState createState() => _DebugWidgetState();
}
class _DebugWidgetState extends State<DebugWidget> {
int _itemsCount = 1;
#override
Widget build(BuildContext context) {
Widget child = Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Enter restaurant manually'),
onPressed: () {
print('Button pressed');
},
),
RaisedButton(
child: Text('+1'),
onPressed: () {
setState(() {
_itemsCount += 1;
});
},
),
RaisedButton(
child: Text('-1'),
onPressed: () {
setState(() {
_itemsCount -= 1;
});
},
),
],
),
LimitedBox(
maxHeight: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: _itemsCount,
),
),
]
)
),
Text(
'Restaurants nearby',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
);
return Scaffold(
body: child,
);
}
}
I found a solution to this problem. you should wrap your ListView with LimittedBox or ConstraintBox and give them maxHeight and set shrinkWrap property of ListView to true. the solution would be something like this.
LimitedBox(
maxHeight: 200,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.cyan,
),
title: Text('Test restaurant'),
subtitle: Text('80m'),
);
},
itemCount: 15,
),
),
I see that this question has never been answered only with giving a fixed height, so here is what works for me.
For some reason if you set the shrinkwrap to true it doesn't look like it is working but it does, the problem is in the padding settings of the ListView, set the padding to edgeinstets.zero. That fixes it for me.
Wrap inside a Flexible
ShrinkWrap true
Padding, zero
and if needed the column to MainAxisSize.min.
Hope it helps some people.
Example of my code:
Flexible(
child: Container(
decoration: BStyles.cardDecoration1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'PRODUCTION TASKS',
),
const SizedBox(
height: textVerticalSpacing,
),
Flexible(
child: ListView.builder(
itemCount: recentTasks.length,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return TaskCard(
task: recentTasks[index],
widthInfo: MediaQuery.of(context).size.width * 0.6,
);
},
),
),
const SizedBox(
height: itemSpacing,
),
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () { },
child: const Text(
'View more',
),
),
),
const SizedBox(
height: textVerticalSpacing,
),
],
),
),
),
),
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200.0),
child: [your child here],
)
This make your child's height not bigger than 200.0
You can always size the ListView container as % of the viewport (assuming of course that the other widgets also are sized in the same manner):
return Container(
height: MediaQuery.of(context).size.height * 0.75,
child: ListView.builder(
itemBuilder: (ctx, index) {
return Card(...