Reputation: 1012
I'm trying to build a layout where there are two Text objects at the top and bottom which stays stationery and a ListView at their center.
Here's the code for the Screen
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(vertical: 40.0),
child: Text(
DateFormat("hh:mm 'PM ,' MMMM d").format(DateTime.now()),
style: Theme.of(context).textTheme.title,
),
),
Expanded(
child: ListView.builder(
itemCount: 4,
itemBuilder: (BuildContext context, int index) =>
CustomAppText(
text: 'Custom App',
),
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 40.0),
child: Text(
"Settings",
style: Theme.of(context).textTheme.title,
),
),
],
),
),
),
);
}
}
I have tried using the Center widget but it does not center the ListView
Upvotes: 15
Views: 72691
Reputation: 3356
It have to use shrinkWrap: true and Flexible together to show all items of ListView.
Flexible(
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: models.length,
Upvotes: 0
Reputation: 1012
The ListView fills the entire Expanded Widget, that's why using the Center widget didn't work, so shrinkWrap: true
should be added so the ListView takes only the height of it's children.
After skimming through the documentation I found about Flexible Widget
Flexible, which does not force the child to fill the available space.
Made the change and works like a charm
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemCount: 4,
itemBuilder: (BuildContext context, int index) =>
CustomAppText(
text: 'Custom App',
),
),
),
Upvotes: 39
Reputation: 177
Add two spacer it will give you 100% same result as you expected
Spacer(),
Expanded(
child: ListView.builder(
itemCount: 4,
itemBuilder: (BuildContext context, int index) =>
CustomAppText(
text: 'Custom App',
),
),
),
Spacer(),
Upvotes: 1
Reputation: 728
For those still looking for an answer, this is what worked for me:
Column(
children: [
Container(), // some top content
Expanded(
child: Center(
child: ListView(
shrinkWrap: true,
children: [] //your list view content here
)
)
),
Container(), // some bottom content
]
)
The Expanded widget makes the content take up all available space.
The Center widget centers the content you want to display.
The ListView holds your list content and the "shrinkWrap: true" property makes your list view shrink according to content size(allowing it to centralized by the Center widget when it's not taking a lot of space).
Upvotes: 25
Reputation: 1
Just wrap your ListView.builder inside a container class and give it a height, either explicitly in double or as a percentage of screen height.
class Trial extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(vertical: 40.0),
child: Text(
"Some Text",
style: Theme.of(context).textTheme.title,
),
),
Container(
// height: 40,
height: MediaQuery.of(context).size.height * 0.4,
child: ListView.builder(
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Text("Hello");
}
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 40.0),
child: Text(
"Settings",
style: Theme.of(context).textTheme.title,
),
),
],
),
),
),
);
}
}
Upvotes: 0
Reputation: 2709
Hope it helps. Give the top and bottom widgets the 25% of the screen size. Give the listview the 50% of the screen size.
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
@override
Widget build(BuildContext context) {
final _size = MediaQuery.of(context).size;
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(28.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Top Widgets
Container(
width: double.infinity,
// color: Colors.green,
height: _size.height * 0.25, // Take 25% width of the screen height
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('11: 25 AM', style: TextStyle(fontSize: 23.0),),
Text('Set As Launcher', style: TextStyle(fontSize: 23.0),)
],
),
),
Expanded(
child: Container(
// color: Colors.yellow,
child: ListView(
children: List.generate(25, (index){
return Text('Custom App $index', style: TextStyle(fontSize: 45.0),);
}),
),
),
),
// Bottom Widgets
Container(
width: double.infinity,
// color: Colors.blue,
height: _size.height * 0.25, // Take 25% width of the screen height
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Settings', style: TextStyle(fontSize: 23.0),),
],
),
)
],
),
),
),
);
}
}
Upvotes: 2
Reputation: 103421
Just add an Expanded
as a wrapper for your first Container
inside the Column
Expanded(
child: Container(
margin: EdgeInsets.symmetric(vertical: 40.0),
child: Text(
DateFormat("hh:mm 'PM ,' MMMM d").format(DateTime.now()),
style: Theme.of(context).textTheme.title,
),
),
),
Upvotes: 1
Reputation: 15683
If you replace your Expanded
widget with a Container
and give that a fixed height
, I think you get what you are looking for.
Upvotes: -1