I have a Widget list with millions of widgets and some of them are wider than screen.
I need to use ListView.builder() and ListTile to save time while running like this:
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
controller: scrollController,
itemCount: widgetList.length,
itemBuilder: (context, i) =>
ListTile(
title: widgetList[i]
)
);
But when I run it, those ListTile that their title is wider than screen will overflow on the right because ListView.builder() not wide enough.
If I assign a big width to ListView.builder() like this will works fine but will remain a lot of blank even if all widgets in list are short:
ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: [
Container(
width: 2000,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
controller: scrollController,
itemCount: widgetList.length,
itemBuilder: (context, i) =>
ListTile(
title: widgetList[i]
)
))]);
Any idea to improve this function?
---------------update-----------
My widgetList contains Column/Row etc.
But let's start with only one Text().
Example:
ListView.builder(
restorationId: 'sampleItemListView',
itemCount: 1000000,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz",
maxLines: 1,
),
);
},
)
The text is too long but I don't want it change line .
What can I do to read full text?
Use like below, do not specify the hight and width for the widgets
#override
Widget build(BuildContext context) {
var items = List<SampleItem>.generate(
1000,
(i) => const SampleItem(
'范植勝',
'Showing long widget list using ListView.builder() and ListTile',
Icons.favorite,
));
return Scaffold(
body: ListView.builder(
restorationId: 'sampleItemListView',
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
final item = items[index];
return ListTile(
title: Text(item.name),
subtitle: Text(item.decsription),
leading: Icon(item.icons),
onTap: () {
Navigator.restorablePushNamed(
context,
SampleItemDetailsView.routeName,
);
});
},
),
);
}
Related
I have this code:
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => addProductClass()),
);
},
child: const Icon(
Icons.add,
color: Colors.black,
),
),
body: Column(children: [
FutureBuilder(
future: getDocId(),
builder: (context, snapshot) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: dataIDs.length,
itemBuilder: (BuildContext context, int index) {
return GetProduct(
documentId: dataIDs[index],
);
},
);
}),
Text("text")
]));
}
And i want to use scrollDirection: Axis.horizontal for listview. When I insert this value, I got the error:
Horizontal viewport was given unbounded height
Viewports expand in the cross axis to fill their container and '
'constrain their children to match their extent in the cross axis. '
'In this case, a horizontal viewport was given an unlimited amount of '
'vertical space in which to expand
How can I resolve this?
Easiest way is to provide a fixed height, either using a SizedBox or a ConstrainedBox with a maxHeight set.
Try to set shrinkwrap to true for listview builder
here is an example of listview builder in horizontal mode :
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (BuildContext context, int index){
return Container( margin: EdgeInsets.all(5), height:10, width:20, color:black);
}
),
),
hope it will help !
Flutter newbie here!
Currently, my Scaffold has 2 listview builders and the bottom one is giving me the unbounded height (!constraints.hasBoundedHeight error) issue.
I have tried using shrinkWrap on all 3 list views, as suggested in similar questions but I get the same error.
The only thing that works is wrapping the FutureBuilder in a SizedBox. But that seems unintuitive to me, as I would want it to ideally expand as needed and be scrollable.
My rough solution is to maybe dynamically calculate the height based on the number of items the FutureBuilder needs, but again, I feel there should be a better solution.
My code snippet is attached below:
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 2,
itemBuilder: (context, index) {
return const SuggestCard(
indexKey: 'takt',
);
}),
FutureBuilder<AnimeDetails>(
future: _animeDetail,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 2, //Number of anime from list
itemBuilder: (context, index) {
var anime = snapshot.data; //Get the data from the index
return AnimeCard(
anime: anime,
);
});
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
],
),
);
As per your comment I think below link will helpful to you.
Lists
The parent ListView handling scroll event for body and while second ListView will have fixed height, you can do it like this
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => ListView(
children: [
SizedBox(
height: constraints.maxHeight * .3,
child: ListView.builder(
itemCount: 122,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => Text("H $index"),
),
),
ListView.builder(
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(), // parent controll the scroll event
itemCount: 44,
itemBuilder: (context, index) => Text("$index"),
),
],
),
));
I just added the below lines to your code. You can try the below code.
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 2,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return const SuggestCard(
indexKey: 'takt',
);
}),
FutureBuilder<AnimeDetails>(
future: _animeDetail,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 2, //Number of anime from list
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
var anime = snapshot.data; //Get the data from the index
return AnimeCard(
anime: anime,
);
});
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
],
),
);
I have used the following widget to show some dropdown from api. If I used static variable, then a I can get only the value which is selected from the last dropdown field. How can I get all value which have been selected from all the fields?
ExpansionTile(
iconColor: Color(PrimaryColor),
collapsedIconColor: Color(PrimaryColor),
key: new Key(_key.toString()),
initiallyExpanded: false,
title: new Text(this.dropDownValue),
//backgroundColor: Theme.of(context).accentColor.withOpacity(0.025),
children: [
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: widget.values.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(widget.values[index].name, style: textStyle),
onTap: () {
setState(() {
this.dropDownValue = widget.values[index].name;
_collapse();
});
print(widget.values[index].value);
},
);
}),
]),
Dropdown Image
I want to create a ToDo-App that saves the ToDo's in Firestore.
I am already able to add every new ToDo Item to Firestore and now I want those Items that were added to pop up when the application opens.
I have made the following:
body: Column(
children:<Widget>[
StreamBuilder<QuerySnapshot>(
stream:FirebaseFirestore.instance.collection("TO-DO-Collection").snapshots(),
builder: (context,snapshot){
if(!snapshot.hasData) return LinearProgressIndicator();
return Expanded(
child: _buildList(snapshot.requireData),
);
},
),
Expanded(
child:ListView(
children: _getItems(),
),
),
],
),
Here the method to build the List with all the stored ToDo's:
Widget _buildList(QuerySnapshot snapshot){
return ListView.builder(
itemCount: snapshot.docs.length,
itemBuilder: (context,index){
final doc=snapshot.docs[index];
return _buildTodoItem(doc["task"]);
},
);
}
(The function _buildTodoItem simply returns a List Tile)
This creates two ListViews (one of the first half of the screen and the other one on the other). Is there any possible way to unify both?
Wrap your column with SingleChildScrollView and put physics: NeverScrollableScrollPhysics(). This will merge the scroll of both of your lists.
body: SingleChildScrollView(
child :Column(
children:<Widget>[
StreamBuilder<QuerySnapshot>(
stream:FirebaseFirestore.instance.collection("TO-DO-Collection").snapshots(),
builder: (context,snapshot){
if(!snapshot.hasData) return LinearProgressIndicator();
return _buildList(snapshot.requireData);
},
),
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: _getItems(),
),
],
),),
Widget _buildList(QuerySnapshot snapshot) {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: snapshot.docs.length,
itemBuilder: (context, index) {
final doc = snapshot.docs[index];
return _buildTodoItem(doc["task"]);
},
);
}
I have a ScrollController in my page to work with infinite scroll but when the list builder is not in a Container the ScrollController listeners does not work.
Works
Container(
height: 400,
child: Observer(
builder: (_) {
return ListView.builder(
shrinkWrap: true,
controller: _scrollController,
itemCount: passeiosController.passeios.length,
itemBuilder: (_, index) => PasseioCard(
passeioModel: passeiosController.passeios[index],
),
);
},
),
)
Not working
Observer(
builder: (_) {
return ListView.builder(
shrinkWrap: true,
controller: _scrollController,
itemCount: passeiosController.passeios.length,
itemBuilder: (_, index) => PasseioCard(
passeioModel: passeiosController.passeios[index],
),
);
},
)
It worked. I had a list view builder inside a listview. Putting the controller in the parent listview worked correctly.