I am trying to make a scrollable screen where I could have each different images vertically with a few functions like a star rating bar and maybe a few buttons. I am first trying to insert a photo into the scrollable screen. Here is my code:
`
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
expandedHeight:250,
pinned: true,
floating: true,
flexibleSpace: FlexibleSpaceBar(
background: Container(
padding: EdgeInsets.symmetric(horizontal: AppLayout.getWidth(20)),
child: Column(
children: [
Gap(AppLayout.getHeight(20)),
Row( // text
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"review", style: Styles.headLineStyle1,
),
],
)
],
),
Gap(AppLayout.getHeight(25)),
Container( //search bar
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(AppLayout.getHeight(10)),
color: const Color(0xFFF4F6FD)
),
padding: EdgeInsets.symmetric(horizontal: AppLayout.getWidth(12), vertical: AppLayout.getHeight(12)),
child: Row(
children: [
const Icon(FluentSystemIcons.ic_fluent_search_regular, color: Color(0xFFBFC205)),
Text(
"place, restaurant",
style: Styles.headLineStyle4,
)
],
),
),
],
),
),
),
),
`
The code that gets an error:
`
SliverList(
delegate: SliverChildListDelegate(
(BuildContext context, int index) {
return _buildListItem(foodList2[index]);
},
),
),
`
The foodList2 List:
`
static const List<Tuple4> foodList2 = [
Tuple4<String, String, String, String> (
'assets/images/eel.jpg',
'assets/images/aburasoba.jpg',
'assets/images/soba.jpg',
'assets/images/okonomiyaki.jpg',
)
];
`
I tried to find information about SliverList and more information about SliverChildListDelegate and I figured out that this error dissapears when I delete the body. I do want to keep this body so would there be a way to fix this? (I do know that I don't have a _buildListItem in my code right now)
If you want to use a builder method, you need to use SliverChildBuilderDelegate instead of SliverChildListDelegate.
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return _buildListItem(foodList2[index]);
},
),
),
Also remember that your _buildListItem needs to return a Widget
I am trying to create a nested list view each wrapped by a column. The parent widget (widget 1) has a column with a vertical list view and each list view item (widget 2) is a column with a horizontal list view. So far I am able to get it to render with the following code where in widget 2 I wrap the horizontal list view with a Container and a specified height. I am trying to use not use a fixed height, however, so I have tried using Flexible and Expanded instead of Container but both of these result in the unbounded height constraints error.
class Widget1State extends State<Widget1> {
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Flexible(
child: Scrollbar(
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: getWidgets().length,
itemBuilder: (BuildContext context, int index) {
return Widget2();
},
),
),
),
],
),
);
}
}
class Widget2State extends State<Widget2> {
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
height: 30,
child: Scrollbar(
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
scrollDirection: Axis.horizontal,
itemCount: getWidgets2().length,
itemBuilder: (BuildContext context, int index) {
return Text('widget');
},
),
),
),
],
);
}
}
As you can see below this is how it currently works where the exercises is the parent list view and the sets are the child list view. Currently because the sets list is in a Container it takes up space when it's empty and also doesn't size to whatever makes up the list item. I want to change the sets list view so that it only takes up the space is needed by the list item.
Given that Listview takes all avaible height if you dont provide one it will result in failure.
In order to proovide alternative solutions I need you especify how is the design that you want. Coudl you give more details?
---- Edited:
This solution was found here: Flutter: Minimum height on horizontal list view
You can change the widget 2 from Listview to SingleChildScrollView:
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
const Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(label: Text('Workout Name')),
),
),
...List.generate(
exercises, // number of exercises
(index) => Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownButton<String>(items: const [
DropdownMenuItem(child: Text('Select Exercise'))
], onChanged: (value) {}),
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Row(
children: List.generate(
sets, //number of sets
(index) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Set $index'),
Text('reps'),
Text('rest')
],
)),
)),
TextButton.icon(
onPressed: () {
addSet();
},
icon: const Icon(Icons.add),
label: Text('Set'))
],
))
],
),
bottomNavigationBar: IconButton(
onPressed: () {
addExercise();
},
icon: const Icon(Icons.add)),
);
}
I've tried this code and works as you need, without setting the height of the 'Sets' scrollview.
I want to point the use of the bottomNavigationBar to the AddExercise button, instead of a Column>Listview structure. Separating the button in the bottomNavBar you can use the body atribute freely.
You want to use Flutter default widgets when posible.
Im trying to remove the scrolling of my ListView widget. Currently, the user only has a small window of tiles to scroll through. The listview data is paged so only shows 20 items at once- i want to show all 20 items and the whole page to scroll, rather than the user scroll through the list view a few at a time. How can i achieve this?
return Column(
children: [
Expanded(
child: ListView.separated(
separatorBuilder: (context, index) => Container(
height: 1,
color: Constants.listSeparatorGrey,
),
itemCount: pageState.data?.data?.length ?? 0,
itemBuilder: (context, idx) =>
itemBuilder(pageState.data?.data?[idx]),
),
),
Text('${pageState.data?.total ?? 0} results',
style: TextStyles.rowHeader(context)),
Text(
'Page ${pageState.data?.currentPage()} of ${pageState.data?.pageNum()}',
style: TextStyles.rowHeader(context),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(width: 20),
if (pageState.data?.hasPrev ?? false)
MyButton(
// isLoading: pageState is Loading,
type: ButtonType.secondary,
label: "Previous",
onPressed: pageApi.prev,
)
else
Container(width: 8),
const SizedBox(
width: 8,
),
(pageState.data?.hasNext ?? false)
? MyButton(
// isLoading: pageState is Loading,
type: ButtonType.secondary,
label: "Next",
onPressed: pageApi.next,
)
: const SizedBox(width: 8)
],
),
],
);
If I correctly understand you. Just move all your content to ListView. So all your page starts scrolling with content.
Widget header = Container(color: Colors.green, height: 100);
List<Widget> content = const [Text("firstCell"), Text("secondCell")];
Widget button =
const TextButton(onPressed: null, child: Text("Next page"));
List<Widget> widgets = [header] + content + [button];
return Scaffold(
appBar: AppBar(
title: const Text('All content in list'),
),
body: ListView(children: widgets),
);
Here result:
All content in ListView
I solved my problem.
I just put the root column in a SingleChildScrollView()
very simple in the end
This is the problem:
I have a grid (a crossword) and a list of questions below it. I need the list of questions to scroll indipendently from the grid. When I click on the grid to type the answer and the keyboard comes up I get an overflow error AND the grid doesn't move so the focused textfield that I use to input the answer is not visible (if it's low enough on the grid to be covered by the keyboard).
I tried all kind of combinations with ListView and Expanded widgets...no solution...I cannot use resizeToAvoidBottomInset: false because I need the grid to move up and keep the focused TextField visible.
Here is the code:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children:[
FutureBuilder(
future: grid,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Align(
alignment: Alignment.topCenter,
child: Container(
width: MediaQuery.of(context).size.width-8,
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
child: GridView.count(
padding: EdgeInsets.only(left:0.0,top:5.0,right:0.0,bottom: 0.0),
shrinkWrap: true,
crossAxisCount: 15,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
children: List.generate(snapshot.data.length, (index) {
if(gridFilled.length < snapshot.data.length) {
gridFilled.add(snapshot.data[index]);
}
return FocusScope(
node: _node,
child: Container(
decoration: BoxDecoration(
color: snapshot.data[index] == "#" ? Colors.black : Colors.white,
border: Border.all(color: Colors.black)),
child:
snapshot.data[index] == "#"
? Text('#')
: _isTextField(gridFilled[index], index),
));
}),
),
),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
SizedBox(width: MediaQuery.of(context).size.width, height: 15.0,),
Expanded(
child: QPanel(dir: widget.dir, dbName: widget.xwordnumber),//this is a ListView with the questions
),
]),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children:<Widget>[
//just menu items
]
),
),
);
}
Unfortunately I'm not allowed to post pictures yet...not enough reputation..please, any help would be greatly appreciated!
wrap your Column inside SingleChildScrollView.
for example:
SingleChildScrollView(
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text('We move under cover and we move as one'),
Text('Through the night, we have one shot to live another day'),
Text('We cannot let a stray gunshot give us away'),
Text('We will fight up close, seize the moment and stay in it'),
Text('It’s either that or meet the business end of a bayonet'),
Text('The code word is ‘Rochambeau,’ dig me?'),
],
)
)
you can wrap your entire column inside SingleChildScrollView()
I am trying to achieve a very common behavior nowadays which is to have a horizontal List within another widget that is at the same time scrollable. Think something like the home screen of the IMDb app:
So I want to have a widget that scrolls vertically with few items on them. At the top of it, there should be a horizontal ListView, followed up with some items called motivationCard. There are some headers in between the list and the cards as well.
I got something like this on my Widget:
#override
Widget build(BuildContext context) => BlocBuilder<HomeEvent, HomeState>(
bloc: _homeBloc,
builder: (BuildContext context, HomeState state) => Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Text(
Strings.dailyTasks,
),
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: tasks.length,
itemBuilder: (BuildContext context, int index) =>
taskCard(
taskNumber: index + 1,
taskTotal: tasks.length,
task: tasks[index],
),
),
Text(
Strings.motivations,
),
motivationCard(
motivation: Motivation(
title: 'Motivation 1',
description:
'this is a description of the motivation'),
),
motivationCard(
motivation: Motivation(
title: 'Motivation 2',
description:
'this is a description of the motivation'),
),
motivationCard(
motivation: Motivation(
title: 'Motivation 3',
description:
'this is a description of the motivation'),
),
],
),
),
);
this is the error I get:
I/flutter (23780): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (23780): The following assertion was thrown during performResize():
I/flutter (23780): Horizontal viewport was given unbounded height.
I/flutter (23780): Viewports expand in the cross axis to fill their container and constrain their children to match
I/flutter (23780): their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of
I/flutter (23780): vertical space in which to expand.
I have tried:
Wrapping the ListView with an Expanded widget
Wrapping the Column with SingleChildScrollView > ConstrainedBox > IntrinsicHeight
Having CustomScrollView as a parent, with a SliverList and the List within a SliverChildListDelegate
None of these work and I continue getting the same kind of error. This is a very common thing and shouldn't be any hard, somehow I just cannot get it to work :(
Any help would be much appreciated, thanks!
Edit:
I thought this could help me but it didn't.
Well, Your Code Work Fine with wrapping your- ListView.builder with Expanded Widget &
setting mainAxisSize: MainAxisSize.min, of Column Widget.
E.x Code of what you Have.
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Headline',
style: TextStyle(fontSize: 18),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 15,
itemBuilder: (BuildContext context, int index) => Card(
child: Center(child: Text('Dummy Card Text')),
),
),
),
Text(
'Demo Headline 2',
style: TextStyle(fontSize: 18),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx,int){
return Card(
child: ListTile(
title: Text('Motivation $int'),
subtitle: Text('this is a description of the motivation')),
);
},
),
),
],
),
Update:
Whole page Is Scroll-able with - SingleChildScrollView.
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Headline',
style: TextStyle(fontSize: 18),
),
SizedBox(
height: 200.0,
child: ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 15,
itemBuilder: (BuildContext context, int index) => Card(
child: Center(child: Text('Dummy Card Text')),
),
),
),
Text(
'Demo Headline 2',
style: TextStyle(fontSize: 18),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
],
),
),
Screenshot:
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: 7,
itemBuilder: (_, i) {
if (i < 2)
return _buildBox(color: Colors.blue);
else if (i == 3)
return _horizontalListView();
else
return _buildBox(color: Colors.blue);
},
),
);
}
Widget _horizontalListView() {
return SizedBox(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (_, __) => _buildBox(color: Colors.orange),
),
);
}
Widget _buildBox({Color color}) => Container(margin: EdgeInsets.all(12), height: 100, width: 200, color: color);
}
We have to use SingleScrollView inside another SingleScrollView, using ListView will require fixed height
SingleChildScrollView(
child: Column(
children: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [Text('H1'), Text('H2'), Text('H3')])),
Text('V1'),
Text('V2'),
Text('V3')]))
If someone gets the renderview port was exceeded error. warp your ListView in a Container widget and give it the height and width property to fix the issue
Column(
children: <Widget>[
Text(
Strings.dailyTasks,
),
Container(
height: 60,
width: double.infinity,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: tasks.length,
itemBuilder: (BuildContext context, int index) =>
taskCard(
taskNumber: index + 1,
taskTotal: tasks.length,
task: tasks[index],
),
),
)
]
)
I tried in this code and I fixed my problem I hope solved your want it.
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
item(),
item(),
item(),
item(),
],
),
),
Horizontal ListView inside Vertical ListView using Builder
None of the answers proved to solve my issue, which was to have a horizontal ListView inside a Vertical ListView while still using ListBuilder (which is more performant than simply rendering all child elements at once).
Turned out it was rather simple. Simply wrap your vertical list child inside a Column, and check if index is 0 (or index % 3 == 0) then render the horizontal list.
Seems to work fine:
final verticalListItems = [];
final horizontalListItems = [];
ListView.builder(
shrinkWrap: true,
itemCount: verticalListItems.length,
itemBuilder: (context, vIndex) {
final Chat chat = verticalListItems[vIndex];
return Column( // Wrap your child inside this column
children: [
// And then conditionally render your Horizontal list
if (vIndex == 0) ListView.builder(itemCount: horizontalListItems.length itemBuilder: (context, hIndex) => Text('Horizontal List $hIndex')),
// Vertical list
Text('Item No. $vIndex')
],
);
},
),
for Web Chome you have to add MaterialScrollBehavior for horizontal scrolling to work. see(Horizontal listview not scrolling on web but scrolling on mobile) I demonstrate how to use the scrollcontroller to animate the list both left and right.
import 'package:flutter/gestures.dart';
class MyCustomScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
#override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
return MaterialApp(
title: 'Flutter Demo',
scrollBehavior: MyCustomScrollBehavior(),
)
class TestHorizontalListView extends StatefulWidget {
TestHorizontalListView({Key? key}) : super(key: key);
#override
State<TestHorizontalListView> createState() => _TestHorizontalListViewState();
}
class _TestHorizontalListViewState extends State<TestHorizontalListView> {
List<String> lstData=['A','B','C','D','E','F','G'];
final ScrollController _scrollcontroller = ScrollController();
_buildCard(String value)
{
return Expanded(child:Container(
margin: const EdgeInsets.symmetric(vertical: 20.0),
width:300,height:400,child:Card(child: Expanded(child:Text(value,textAlign: TextAlign.center, style:TextStyle(fontSize:30))),)));
}
void _scrollRight() {
_scrollcontroller.animateTo(
_scrollcontroller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
void _scrollLeft() {
_scrollcontroller.animateTo(
0,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
_segment1()
{
return SingleChildScrollView(child:
Expanded(child:
Container(height:300,
width:MediaQuery.of(context).size.width,
child:Row(children: [
FloatingActionButton.small(onPressed: _scrollRight, child: const Icon(Icons.arrow_right),),
Expanded(child:Scrollbar(child:ListView.builder(
itemCount: lstData.length,
controller: _scrollcontroller,
scrollDirection: Axis.horizontal,
itemBuilder:(context,index)
{
return _buildCard(lstData[index]);
})
,),
),
FloatingActionButton.small(onPressed: _scrollLeft, child: const Icon(Icons.arrow_left),),
]))
,
)
);
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("horizontal listview",)),body:
segment1(),
);
}
}
You just have to fix your height of your Listview (by wrapping it in a SizedBox for example).
This is because the content of your listview can't be known before the frame is drawn. Just imagine a list of hundreds of items.. There is no way to directly know the maximum height among all of them.