I'm trying to create a page which contains multiple sections and each section is generated using ListView.builder().
Here the page problem I'm facing is that , the page is not being scrolled unless the touch is not focused on the widget generated with ListView.
Widget _widget1(BuildContext context){
return ListView.builder(
....
.....
);
}
Widget _widget2(BuildContext context){
return ListView.builder(
....
.....
);
}
Widget _widget3(BuildContext context){
return ListView.builder(
....
.....
);
}
body: Container(
child: ListView(
scrollDirection: Axis.vertical,
physics: PageScrollPhysics(),
shrinkWrap: true,
children: <Widget>[
Container(
height: 140.0,
child: _offersBanner(context)
),
_widget1(context),
_widget2(context),
_widget3(context)
],
)
)
try this,
please add below code inside ListView.builder
shrinkWrap: true,
physics: ClampingScrollPhysics(),
Do you want four scrolling lists or just one combined list?
If you want the former what you've done should work the way you want.
If you want the latter (a combined list) then you should use column instead of listview in your _widget1, _widget2 and _widget3 classes.
I guess you need the latter.
Widget _widget1(BuildContext context){
return Column(
....
.....
);
}
Widget _widget2(BuildContext context){
return Column(
....
.....
);
}
Widget _widget3(BuildContext context){
return Column(
....
.....
);
}
body: Container(
child: ListView(
scrollDirection: Axis.vertical,
physics: PageScrollPhysics(),
shrinkWrap: true,
children: <Widget>[
Container(
height: 140.0,
child: _offersBanner(context)
),
_widget1(context),
_widget2(context),
_widget3(context)
],
)
)
Related
UPDATE: I keep getting an error when i try and use a listView pretty much i need 3 list view on 3 layers of columns and each has a horizontal scrollable list view
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Widget horizontalList1 = new Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(width: 130.0, color: Colors.red,),
],
)
);
Widget horizontalList2 = new Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(width: 130.0, color: Colors.blue,),
],
)
);
Widget horizontalList3 = new Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(width: 130.0, color: Colors.blue,),
],
)
);
return new Scaffold(
appBar: new AppBar(
title: new Text("Activity"),
),
body: new Center(
child: new Container(
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
horizontalList1,
horizontalList2,
horizontalList3,
],
),
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
So pretty much this should work but i keep getting a mediaquery error and have no clue what i am missing or what's causing the error
When you are using a ListView inside another ListView the first one should have a specific size
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Widget horizontalList1 = new Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 200, //<- Here the height should be specific
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 130.0,
color: Colors.red,
),
],
));
Widget horizontalList2 = new Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 200,//<- Here the height should be specific
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 130.0,
color: Colors.blue,
),
],
));
Widget horizontalList3 = new Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 200,//<- Here the height should be specific
child: new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 130.0,
color: Colors.blue,
),
],
));
return new Scaffold(
appBar: new AppBar(
title: new Text("Activity"),
),
body: new Center(
child: new Container(
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
horizontalList1,
horizontalList2,
horizontalList3,
],
),
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Your error says MediaQuery.of() was called on a context that does not contain a MediaQuery
It's Because You are using Scaffold for your app's parent widget.But scaffold should be used for a page not an app.
You should use MaterialApp for the parent widget of your app.
#override
Widget build(BuildContext context) {
return MaterialApp(
home:Scaffold(
//Your code here
)
);
}
I am building a listview from a Firestore Database. I originally wanted to separate my items by ListTiles since I know they can do separators, but I was not getting the height that I wanted out of the tiles, so I moved to transparent Cards.
Problem is I cannot figure out how to add a separator or divider after each card.
Here is my code so far
Widget build(BuildContext context) {
if (snapshot == null) return CircularProgressIndicator();
return Scaffold(
body: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index){
return Card(
elevation: 0,
color: Colors.transparent,
child: Row(
children: <Widget>[
Padding(padding: EdgeInsets.all(10.0),),
Column(
children: <Widget>[
Padding(padding: EdgeInsets.all(10.0),),
Text(snapshot[index].data["month"], style:
TextStyle(fontSize: 30, fontWeight:
FontWeight.w300),),
Text(snapshot[index].data["day"], style:
TextStyle(fontSize: 20),),
],
)
],
),
);
}
),
);
}
}
Desired
Current
I would think list tiles would work better, but I tried what I knew how to do to build custom list tiles and i could not replicate the results.
Use ListView.separated
ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
itemCount: 20,
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.all(8.0),
child: Center(child: Text("Index $index")),
),
)
or divideTiles()
ListView(
children: ListTile.divideTiles(
context: context,
tiles: [
// your widgets here
]
).toList(),
)
I'm making a new stateful widget that would show a listview according to the option selected, which are ONE and TWO here. The value of index changes once the GestureDetector is tapped, fontsize and color of the text changes. but, the Container with pages[index] does not rebuild
I don't know what is wrong since, one of the container in the column rebuilds and the other doesn't.
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MatchStatsState();
}
}
class MatchStatsState extends State<MatchStats>{
List<Widget> pages = [
ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
BattingStatsView(CskBatting),
BowlingStatsView(cskBowling),
],
),
ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
BattingStatsView(kxipBatting),
BowlingStatsView(kxipBowling)
],
),
];
Color activeColor = Colors.yellow;
Color inactiveColor = Colors.white;
num activeFontSize = 20.0;
num inactiveFontSize = 15.0;
int index = 0;
#override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
height: MediaQuery.of(context).size.height*0.4,
width: MediaQuery.of(context).size.width*0.95,
child: Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height*0.05,
width: MediaQuery.of(context).size.width*0.95,
child: Row(
children: <Widget>[
GestureDetector(
onTap: (){
setState(() {
index = 0;
});
},
child: Container(
width: MediaQuery.of(context).size.width*0.45,
child: Text("ONE",style: TextStyle(color: index == 0?activeColor:inactiveColor,fontSize: index == 0? activeFontSize: inactiveFontSize)),
),
),
GestureDetector(
onTap: (){
setState(() {
index = 1;
});
},
child: Container(
width: MediaQuery.of(context).size.width*0.45,
child: Text("TWO",style: TextStyle(color: index == 1?activeColor:inactiveColor, fontSize: index == 1? activeFontSize: inactiveFontSize)),
),
),
],
),
),
Container(
height: MediaQuery.of(context).size.height*0.35,
width: MediaQuery.of(context).size.width*0.95,
child: pages[index]
),
]
)
);
}
}
I want the second container in the column to rebuild when the value of index changes, how could I achieve that?
Try with this:
create a method that return a List Widget like this:
List<Widget> buildPages() {
return [
ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
BattingStatsView(CskBatting),
BowlingStatsView(cskBowling),
],
),
ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
BattingStatsView(kxipBatting),
BowlingStatsView(kxipBowling)
],
),
];
}
Widget getProperWidget(int index) {
return buildPages()[index];
}
Than your column container:
Container(
height: MediaQuery.of(context).size.height*0.35,
width: MediaQuery.of(context).size.width*0.95,
child: getproperWidget(index)
),
Remember to override the initState.
I think the cause of this issue is the element tree doesn't recognize the change that has been done in the widget tree , so you can add Key to the container which holds pages[index] or
you can do something like this :
Widget getWidget(int index){
return Container(
child:pages[index],
);
}
instead of using Container in the widget tree, use a function that will be called every time the ui re renders .
I hope that can help
When I'm, not using the ListView.builder constructor in Flutter, the individual item is shown as expected from the JSON API:
when I use ListView.builder, nothing shows up. no Error!
I also tried a listview with Texts only that doesn't seem to work either.
Here's the code:
#override
Widget build(BuildContext context) {
return Container(
child: new Scaffold(
appBar: AppBar(
title: Text("the title"),//TODO edit this
backgroundColor: Colors.blueAccent),
body:
Column(
children: <Widget>[
FutureBuilder<List<dynamic>>(
future: getPosts2(),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? ListViewPosts(postsFrom: snapshot.data)
: Center(child: CircularProgressIndicator());
},
),
],
),
),
);
}
}
And here is the ListViewPosts Stateless Widget:
class ListViewPosts extends
StatelessWidget {
final List<dynamic> postsFrom;
ListViewPosts({Key key,
this.postsFrom}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FadeInImage.assetNetwork(
placeholder: 'assets/images/placeholder.png',
image: postsFrom[1]["featured_media"] == 0
? 'assets/images/placeholder.png'
: postsFrom[1]["_embedded"]["wp:featuredmedia"]
[0]["source_url"],
),
FadeInImage.assetNetwork(
placeholder: 'assets/images/placeholder.png',
image: postsFrom[2]["featured_media"] == 0
? 'assets/images/placeholder.png'
: postsFrom[2]["_embedded"]["wp:featuredmedia"]
[0]["source_url"],
),
new Row(
children: <Widget>[
Expanded(
child: Text(
"نووسهر: " +
postsFrom[1]["_embedded"]["author"][0]
["name"],
textAlign: TextAlign.right,
),
),
Expanded(
child: Text(
dateConvertor(
postsFrom[2]["date"].toString()),
textAlign: TextAlign.left,
),
),
],
),
ListView.builder(
itemCount: postsFrom.length, //== null ? 0 : postsFrom.length,
itemBuilder: (context, int index) {
Card(
child: Column(
children: <Widget>[
Text(postsFrom.toString()),
Container(
child: hawalImage(postsFrom, index),
),
new Padding(
padding: EdgeInsets.all(5.0),
child: new ListTile(
title: new Text("whatEver"),
subtitle: new Row(
children: <Widget>[
Expanded(
child: new Text(postsFrom[index]["title"]["rendered"]),
),
Expanded(
child: hawalDate(postsFrom, index),
),
],
),
),
),
new ButtonTheme.bar(
child: hawalBtnBar(),
),
],
),
);
},
),
You have to write return Card at the beginning of the curly brackets in the builder function. Also I would be cautious with using Expanded there, it might cause some errors.
Also you put a ListView inside a Column without defining it's height, so it will take up space indefinitely. Wrap it in a widget that provides height constraints(SizedBox, Expanded, ...)
Inside the Listview.builder() you could try to add the property shrinkWrap: true.
This worked for me. I was facing a similar issue.
Use with Expanded. Hopefully, it will solve your problem.
You have to write return Card at the beginning of the curly brackets in the builder function. Also I would be cautious with using Expanded there, it might cause some errors.
I'm struggling with the ListView.
My problem is that I've a Listview inside another Listview and the second Listview items height are not always the same. I want to get rid of the itemExtent and create an automatically height for the first Listview.
What I really want to acomplish is something like this:
#override
Widget build(BuildContext context) {
return
Column(
children: <Widget>[
TextField(),
Expanded(
child: ListView.builder(
key: new Key("ditisdekeyvoordelistview"),
itemBuilder: _makeMovieList,
padding: EdgeInsets.all(0.0),
itemCount: _movies.length,
itemExtent: 300.0,
),
),
],
);
}
//FIRST LIST
Widget _makeMovieList(BuildContext context, int index) {
return Container(
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
child: Column(mainAxisSize: MainAxisSize.max, children: <Widget>[
Image.network(
_movies[index].movieImage,
fit: BoxFit.cover,
width: 100.0,
)
])),
title: Text(
_movies[index].movieTitle,
),
subtitle: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_makeStarRating(_movies[index].movieRating),
Text(_movies[index].movieDescription),
_makeCardDates(index)
],
),
),
);
}
//SECOND LIST
Widget _makeCardDates(int index) {
return Expanded(
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(0.0),
itemCount: _movies[index].dateTimeList.length,
itemBuilder: (context, indexx) {
return GestureDetector(
onTap: () {
print(_movies[index].dateTimeList[indexx].toString());
},
child: Card(
elevation: 8.0,
color: Color.fromRGBO(64, 75, 96, .9),
child: Column(
children: <Widget>[
Text(_movies[index].cinema),
Text(((dateFormatMovieHours
.format(_movies[index].dateTimeList[indexx]))
.toString())),
],
)));
},
itemExtent: 40.0,
),
);
}
Using itemExtent on a ListView isn't required, though ListView needs to have a finite height set for vertical scroll (default) and finite width is needed for horizontal scroll. Otherwise, the ListView will throw a "constraints are unbounded" error.
For your use case, you can either set height on the list items in the first ListView, or set height on the second ListView. However, if you'd like the second ListView to be non-scrollable and the list items in the first ListView will adapt dynamically, you can use a Column of Widgets similar to this sample.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final items = [
'Apple',
'Banana',
'Carrot',
'Dog',
'Egg',
'Flower',
'Goat',
'Honey'
];
final subItems = ['1.00', '2.00', '3.00', '4.00'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: firstList(),
),
);
}
firstList() {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Card(
child: Container(
color: Colors.lightBlue[50],
padding: EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Text('${items[index]}'),
),
Expanded(
flex: 1,
child: secondList(subItems),
),
],
),
),
),
);
},
);
}
secondList(List item) {
// Create List<Widget> for the second "List"
var subList = List<Widget>();
item.forEach((data) {
subList.add(
Card(
child: Container(
padding: EdgeInsets.all(16.0),
color: Colors.lightBlueAccent,
child: Text('$data'),
),
),
);
});
// Populate Column instead of ListView
return Column(
children: subList,
);
}
}