flutter listview and columns side by side - flutter

I want to create a row with the left side having a listview builder and right side with a container or columns of texts. I have tried the following code but it is showing blank screen
Widget invSection1 = Row(
children: <Widget>[
ListView.builder(
itemCount: 1, // the length
shrinkWrap: true,
itemBuilder: (context, index) {
return Container(
child: Card(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: new List.generate(
10,
(index) => new ListTile(
title: Text('Item $index'),
subtitle: Text('Item $index subtitle'),
trailing: Icon(Icons.shop_two),
),
),
)
)
),
);
}),
Expanded(
child: Text('Craft beautiful UIs', textAlign: TextAlign.center),
)
]);

In this, you have to give some width as the parent, because the parent can size itself based on the children, As you are using the Row widget and the use of listview does not allow it to make specific constraints. just check out the example :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget invSection1 = Row(
children: <Widget>[
Container(
width: 200,
child: ListView.builder(
itemCount: 1, // the length
shrinkWrap: true,
itemBuilder: (context, index) {
return Container(
child: Card(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: new List.generate(
10,
(index) => new ListTile(
title: Text('Item $index'),
subtitle: Text('Item $index subtitle'),
trailing: Icon(Icons.shop_two),
),
),
))),
);
}),
),
Expanded(child: Text('Craft beautiful UIs', textAlign: TextAlign.center))
]);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(child: invSection1),
),
);
}
}

This is expected behavior. Any widget in a row has unlimited space to expand horizontally. The ListView has no constraints on it's width and will attempt to take the maximum available space.
What you can do is limit the horizontal space available to the ListView. This can be done by many approaches, eg. like wrapping it inside a SizedBox and setting a finite width.

Related

How to put a Listview under the existing one Listview. Flutter/Dart

hello there i want to add another one listview on the same screen, how can i do that?
hello there i want to add another one listview on the same screen, how can i do that?
here is my code:
return Scaffold(
appBar: AppBar(title: Text('detailsPage'),
),
body: ListView(
children: [
Card(
child: ListTile(
title:new Center(child:new Text(utf8.decode(appController.userName.runes.toList()) + " " + utf8.decode(appController.userSurname.runes.toList()))),
subtitle:new Center(child:new Text('UserID: '+appController.userid.toString())),
)
),
Card(
child: ListTile(
title:new Center(child:new Text(months[index])),
subtitle:new Center(child:new Text("This month you have done "+appController.Totaleachlength[index].toString()+' charges')),
),
),
Card(
child: ListTile(
title:new Center(child:new Text(appController.Totaleachlist[index].toStringAsFixed(3)+"€")),
subtitle:new Center(child:new Text("Total amount")),
)
),
ElevatedButton(child: Text('Download Bill pdf'),
onPressed: () => ''),
ListTile(
title: new Center(child: new Text('Details of your charges'),),
),
],
shrinkWrap: true,
),
);
if you want to divide your screen, you can use Column
return Scaffold(
appBar: AppBar(title: Text('detailsPage'),),
body : Column(
children: [
Expanded(flex: 2 // you can customize as you need
child: ListView()
),
Expanded(flex: 3 // you can customize as you need
child: ListView()
),
])
Column:(
children: [
ListView1(),
ListView2(),
]
),
If each list didnt scroll, wrap your each one with SingleChildScrollView and if you like to listviews expand all height you can use Expanded
You can also add your another ListView at last child like
ListView:(
children: [
Card()
ListView()
]
)
You have to use shrinkWrap in your child ListView to extend the size in the screen
dont forget to add ClampingScrollPhysics to scroll from parent pehavior
class NestedListView extends StatelessWidget {
const NestedListView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
...List.generate(
20, (index) => Text('Parent List View Index $index')),
ListView(
/// * [ClampingScrollPhysics], which provides the clamping overscroll behavior
physics: const ClampingScrollPhysics(),
/// * [shrinkWrap], which provides the Max size of list in screen
shrinkWrap: true,
children: List.generate(
20, (index) => Text('List View ONE Index $index')),
),
ListView(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
children: List.generate(
20, (index) => Text('List View Two Index $index')),
),
],
),
);
}
}

In Flutter, nested listview without fixed height has a overflow and non-scrollable

In my project, I have implemented a questionnaire format page.
One questionnaire has a many parts (1,2,3 ...) and each part has a many questions.
And, the questions have a many selects (Very bad, bad, so-so, good, Very good, etc.).
To implement this page, I chose a nested listview (inside listview, another listview is existed).
This is a sample code that has a same widget tree with mine.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text('this is text inside 1st column. blue container'),
Column(
children: [
const Text('this is text inside 2nd column. about part title'),
ListView.separated(
shrinkWrap: true,
itemBuilder: (BuildContext firstListViewContext,
int firstListViewIndex) {
return Column(
children: [
const Text(
'this is text inside 1st listview and 3nd column. question title'),
ListView.separated(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Text(
'this is text inside 2nd listview and 3nd column, question selector list');
},
separatorBuilder: (BuildContext context, int index) =>
const SizedBox(height: 4),
itemCount: 20,
),
],
);
},
separatorBuilder: (BuildContext context, int index) =>
const SizedBox(height: 4),
itemCount: 1,
),
],
),
Spacer(),
ElevatedButton(
onPressed: () {},
child: Text('this is button inside 1st column.')),
],
),
);
}
}
Above code has a overflow problem and the question listview cannot be scrolled...
Is there any way I can get rid of overflows in the code above and scroll down the problem list?
Edit 1.
In my code, only question's listview should be scrollable.
The button should be attached to the bottom of the screen.
Try this:
Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text('this is text inside 1st column. blue container'),
Expanded(
child: Column(
children: [
const Text('this is text inside 2nd column. about part title'),
Expanded(
child: ListView.separated(
itemBuilder: (BuildContext firstListViewContext,
int firstListViewIndex) {
return Column(
children: [
const Text(
'this is text inside 1st listview and 3nd column. question title'),
ListView.separated(
physics: NeverScrollableScrollPhysics(),// <---- update: add this
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Text(
'this is text inside 2nd listview and 3nd column, question selector list');
},
separatorBuilder:
(BuildContext context, int index) =>
const SizedBox(height: 4),
itemCount: 20,
),
],
);
},
separatorBuilder: (BuildContext context, int index) =>
const SizedBox(height: 4),
itemCount: 1,
),
),
],
),
),
Spacer(),
ElevatedButton(
onPressed: () {},
child: Text('this is button inside 1st column.')),
],
)

Why does ListView widget returns items as columns?

I'm new to flutter and I'm trying to achieve a simple layout, where the layout is a column of widgets the first item in the column is a text widget, and the second item is a row that contains multiple elevated buttons, this is my code it renders the elevated buttons one under each other instead of rendering it next to each other, so what I'm doing wrong here?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final List<Map<String, dynamic>> questions = [
{
'question': "What's your favorite color?",
'answers': ['Red', 'Blue', 'White', 'Black']
},
{
'question': "What's your favorite animal?",
'answers': ['Dog', 'Cat', 'Lion', 'Monkey']
}
];
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Quiz'),
),
body: Container(
height: double.maxFinite,
child: ListView.builder(
shrinkWrap: true,
itemCount: questions.length,
itemBuilder: (BuildContext context, int questionsIndex) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(height: 20.0,),
Text(questions[questionsIndex]['question']),
SizedBox(height: 10.0,),
ListView.builder(
itemCount:
questions[questionsIndex]['answers'].length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int answerIndex) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: null,
child: Text(questions[questionsIndex]
['answers'][answerIndex]),
),
],
);
}),
SizedBox(height: 20.0,),
]);
}),
),
),
);
}
}
In Flutter ListView renders by default using the Axis.Vertial.
If you want the buttons to render next to each other that is horizontal axis, then you can set the scrollDirection propery of the ListView to Axis.Hortizonal.
If you must use a ListView then you'll need to constrain the height.
Example:
...
SizedBox(
height: 64,
child: ListView.builder(
scrollDirection : Axis.horizontal,
...
)
)

How to make a list of widgets mutate state based on activity on any one widget?

I have a GridView Widget which has a list of Custom Buttons. I want to freeze/disable all the remaining buttons in the list if one of the button in the list is clicked.
How can this be done? I had some ideas around perhaps making a Stateful List Widget that holds the state of whats clicked. But i do not know how to mutate that state. Or broadcast it to all the other objects to manipulate its state. Some guidance would be helpful.
#override
Widget build(BuildContext context) {
final title = 'Grid List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: <Widget>[
Center(
child: Container(
height: 120.0,
width: 120.0,
color: Colors.blue[50],
child: Align(
alignment: Alignment.topRight,
child: FlutterLogo(
size: 60,
),
),
),
),
new Expanded(
child: GridView.count(
// shrinkWrap: false,
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this produces 2 rows.
childAspectRatio: 1.2,
crossAxisCount: 2,
// Generate 100 widgets that display their index in the List.
children: <Center> [
Center(child: Option("Option 1")),
Center(child: Option("Option 2")),
Center(child: Option("Option 3")),
Center(child: Option("Option 4"))
],
)
)
],
),
),
);
}
}
You should employ a state management solution such as riverpod (pub.dev) (docs).
This isn't a scalable example but should be enough to get you started.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final disabledButtonsProvider = StateProvider<List<bool>>((_) => List.generate(4, (_) => false));
class ButtonGrid extends ConsumerWidget {
const ButtonGrid({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, ScopedReader watch) {
final disabledButtons = watch(disabledButtonsProvider).state;
return Scaffold(
body: GridView.count(
crossAxisCount: 2,
children: List.generate(
4,
(index) => ElevatedButton(
onPressed: disabledButtons[index]
? null
: () => context.read(disabledButtonsProvider).state =
List.generate(4, (i) => i != index),
child: Text(index.toString()),
),
),
),
);
}
}

Horizontal ListView inside a Vertical ScrollView in Flutter

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.