Flutter how to dynamically get the height of my page and my Listview.Builder? - flutter

I'm wondering how to get the height of my page dynamically with a Listview.Builder()` inside. This is my page tree:
This is my News.dart
return SafeArea(
child: Scrollbar(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
dragStartBehavior: DragStartBehavior.start,
child: Container(
height: MediaQuery.of(context).size.height * 5,
margin: EdgeInsets.all(25),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
...
Later on we have the Listview.Builder()
Expanded(child: Consumer<Model>(
builder: (context, myModel, child) {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: list.length,
itemBuilder: (ctx, index) =>
ChangeNotifierProvider.value(
value: list[index],
child: GestureDetector(
onTap: () {
setState(() {
},
child: Item(),
),
),
);
})),
Now below my SingleChildScrollView() I have a Container with height of MediaQuery.of(context).size.height * 5, I want to have my complete Screen height dynamic. If I remove the height value, I'm getting the render layout error because there is no parent defining a size. This Page here is Part of a TabbarNavigation and this is the content.
Can anybody tell me how to get the dynamic height of the ListView.Builder() ?
EDIT:
The following is my Tabbar where I define the pages inside the tabbar. One of them is my News.dart
This is the Tabbar.dart:
final List<Widget> _pages = [
NewsScreen(),
TrendScreen(),
OtherScreen(),
];
return Scaffold(
extendBodyBehindAppBar: true,
body: _pages[provider.currentIndex],
bottomNavigationBar: provider.currentIndex != 2
? Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
CustomWidget(),
BottomNavigationBar(
onTap: _selectPage,
backgroundColor: Theme.of(context).primaryColor,
unselectedItemColor: Color.fromRGBO(130, 130, 130, 1),
selectedItemColor: Color.fromRGBO(236, 37, 105, 1),
selectedFontSize: 10,
iconSize: 22,
currentIndex: provider.currentIndex,
type: BottomNavigationBarType.fixed,
selectedLabelStyle: TextStyle(fontSize: 12),
items: [
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.home),
title: Text(
'home',
style: TextStyle(
fontSize: 10,
),
),
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.star),
title: Text(
'News',
style: TextStyle(
fontSize: 10,
),
),
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.play_arrow),
title: Text('other',
style: TextStyle(
fontSize: 10,
)),
),
],
),
])
: null,
);
}

Credits to #pskink !!
Working with CustomScrollView() instead of SingleChildScrollView(), SliverToBoxAdapter() and SliverList() made everything work like charm!
return SafeArea(
child: CustomScrollView(
//scrollDirection: Axis.vertical,
physics: BouncingScrollPhysics(),
slivers: <Widget>[
// Place sliver widgets here
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.fromLTRB(25, 30, 25, 20),
child: SizedBox(
height: 299,
child: Column(children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
...
And a list example:
SliverList(
delegate: SliverChildBuilderDelegate(
(ctx, index) => ChangeNotifierProvider.value(
value: list[index],
child: GestureDetector(
onTap: () {}),
childCount: rrr.length,
)),

You can Use the "Flex" property of the already used Expanded() widget.
first remove the Container at the Top.
return SafeArea(
child: Scrollbar(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
dragStartBehavior: DragStartBehavior.start,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
...
and then,
Column(
children: <Widget>[
Expanded(
flex : 1,
child: Consumer<Model>(
builder: (context, myModel, child) {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: list.length,
itemBuilder: (ctx, index) =>
ChangeNotifierProvider.value(
value: list[index],
child: GestureDetector(
onTap: () {
setState(() {
},
child: Item(),
),
),
;
})),
]),
API Docs : https://api.flutter.dev/flutter/widgets/Expanded-class.html
Flutter Widget of the Week : https://www.youtube.com/watch?v=_rnZaagadyo

Related

Flutter how to remove padding from ExpancionTile

I'm using ExpansionTile in my application, how can I remove padding from ExpansionTile?
I try to set titlePadding and childrenPadding on zero, but it isn't work
My listView.Builder code:
Widget buildExpandableCatalog(List<Catalog> catalog) => ListView.builder(
itemCount: catalog.length,
itemBuilder: (context, index) {
final catalogItem = catalog[index];
return Column(
children: [
Card(
elevation: 0,
child: ExpansionTile(
onExpansionChanged: (a) {
if (catalogItem.hasChild != true) {},
leading: CircleAvatar(),
trailing: catalogItem.hasChild
? Icon(Icons.arrow_drop_down)
: Icon(null),
title: Text(
catalogItem.name,
style: TextStyle(fontSize: 13),
),
children: catalogItem.hasChild
? <Widget>[
Column(
children: getNestedTitles(
index, catalogItem.id, catalogItem.name))
]
: [Column()]),
),
],
);
});
The answer was
Card(
margin: EdgeInsets.zero,

How to put two parallel flutter lists in a column

I wanna put two parallel lists inside the row marked in the picture. I've tried different types of structures, but all give me problems.
Each element of the dynamic lists will have a picture and a Text.
Screen
I've been trying to put two sized box inside the row:
Row(children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
),
])
After the width putting the ListView
Everything I try gives me the next error:
error
Please refer to below code
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
ListView.builder(
physics:
NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 15,
itemBuilder: (BuildContext context,
int index) {
return ListTile(
leading: Icon(
Icons.star_border,
),
title: Text(
'List $index' +
"Lorem ipsum dolor sit amet, ",
),
);
},
),
],
),
),
Flexible(
child: Padding(
padding: EdgeInsets.only(left: 15.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
ListView.builder(
physics:
NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 15,
itemBuilder: (BuildContext context,
int index) {
return Row(
children: [
Icon(
Icons.star,
),
Text("List item $index"),
],
);
},
),
],
),
),
)
],
),
Try this :
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListView.builder(
shrinkWrap:true,
builder:(context,index)=> Container(),
),
ListView.builder(
shrinkWrap:true,
builder:(context,index)=> Container(),
),
],
);

How To Add TabBar with Horizontal And Vertical ListView In One Tab Scrolling In Respective Directions

Flutter newbie here if my code looks too messy. Managed to figure out a few basic layouts and have implemented a TabBar. In 2nd Tab(COMICS). I have a horizontal ListView and a vertical one. I just can't figure out how to make the horizontal ListView scroll without changing tabs.
How i create the tabs:
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
title: Text('NestedScrollView'),
)
];
},
body: Scaffold(
appBar: AppBar(
toolbarHeight: 40,
centerTitle: true,
backgroundColor: Color(0xFFb92136),
title: Text('Kata Kata African Cartoons'),
// actions: [
// IconButton(onPressed: () {}, icon: Icon(Icons.search)),
// IconButton(onPressed: () {}, icon: Icon(Icons.more_vert))
// ],
bottom: TabBar(
controller: tabController,
tabs: [
Tab(
text: "VIDEOS",
),
Tab(
text: "COMICS",
),
Tab(
text: "MAGAZINE",
),
],
),
),
body: TabBarView(
controller: tabController,
children: [
VideosTab(),
ComicsTab(),
Magazines(),
],
),
));
Main body of comics tab
return Column(children: [
Container(child: Card(
elevation: 20,
child: Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: EdgeInsets.all(5),
child: Text("Katakata Long Comics"))
]),
Card(
child: StreamBuilder(
stream: ref.onValue,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData &&
!snapshot.hasError &&
snapshot.data.snapshot.value != null) {
lists.clear();
DataSnapshot dataValues = snapshot.data.snapshot;
Map<dynamic, dynamic> values = dataValues.value as Map;
values.forEach((key, values) {
lists.add(values);
});
return Container(
height: 200,
child: new ListView.builder(
physics: const NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) {
return Card(
margin: EdgeInsets.fromLTRB(2, 2, 2, 2),
elevation: 20,
child: GestureDetector(
onTap: () {
String pdfurl = lists[index]["image"];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PDFViewer(
url: pdfurl,
),
));
},
child: Padding(
padding: EdgeInsets.all(5),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
children: [
Container(
height: 100,
width: 100,
child: Image(
image:
NetworkImage(lists[index]["image"]),
),
),
Text(lists[index]["name"]),
],
),
],
),
),
),
);
},
),
);
}
return Container(child: Text("Add Plants"));
},
),
),
],
),
)),
Container(child: Card(
elevation: 20,
child: Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: EdgeInsets.all(5),
child: Text("Continuous Humour"))
]),
Card(
child: StreamBuilder(
stream: secref.onValue,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData &&
!snapshot.hasError &&
snapshot.data.snapshot.value != null) {
seclists.clear();
DataSnapshot dataValues = snapshot.data.snapshot;
Map<dynamic, dynamic> values = dataValues.value as Map;
values.forEach((key, values) {
seclists.add(values);
});
return new ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: seclists.length,
itemBuilder: (BuildContext context, int index) {
return Card(
margin: EdgeInsets.fromLTRB(2, 2, 2, 2),
elevation: 20,
child: GestureDetector(
onTap: () {
String pdfurl = seclists[index]["image"];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PDFViewer(url: pdfurl,
),
));
},
child: Padding(
padding: EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 200,
width: 400,
child: Image(
image:
NetworkImage(seclists[index]["image"]),
),
),
Text(seclists[index]["name"]),
],
),
),
),
);
},
);
}
return Container(child: Text("Add Plants"));
},
),
),
],
),
)),
]);
You have NeverScrollableScrollPhysics() defined as the physics for your listviews. That means they won't scroll even when there is no tabview around them. Also they won't absorb the scroll event and defer them to the tabview.

Handle listview item height?

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.

Flutter dynamic height of ListView

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(...