Two direction scrolling in data table flutter - flutter

I made a DataTable in flutter and it has about 10 columns and that's more than what the screen can handle so I wrapped the DataTable inside a SingleChildScrollView widget and this solution worked fine until the rows inside the DataTable grew up and exceeded the screen height and I couldn't scroll down because of the scroll direction is set to horizontal in the SingleChildScrollView widget!
And as a temporary solution, I wrapped the DataTable inside a fittedBox inside the SingleChildScrollView but this doesn't solve the whole problem and still, there is some responsibility issues.
What I need is a way to make the DataTable scrollable in both directions horizontally and vertically.
This is my code
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(16),
child: Card(
child: Container(
padding: const EdgeInsets.all(16),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: FutureBuilder(
future: getCategories(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return FittedBox(
child: DataTable(
headingRowColor: MaterialStateProperty.resolveWith(
(states) => Colors.grey.shade900),
columns: _columns,
rows: _rows,
),
);
}
},
),
),
),
),
);
}

The easiest solution I know, is to wrap the SingleChildScrollView in a second SingleChildScrollView.
https://stackoverflow.com/a/57539405/1151983
But there are also other approaches:
https://stackoverflow.com/a/63546017/1151983

Related

Use of Listview.builder makes the screen go away

I want to show Listview underneath my two widgets but when i hot reload, nothing happens and if i run again, UI shows blank screen. If i remove Listview.builder it works fine.
Below is my code.
import 'package:flutter/material.dart';
import 'package:plant_clone/constants.dart';
import 'package:plant_clone/model/model.dart';
import 'package:plant_clone/screens/home/components/header_with_searchbox.dart';
import 'package:plant_clone/screens/home/components/title_with_more_btn.dart';
import 'package:plant_clone/viewmodel/recommended_plants_viewmodel.dart';
class Body extends StatelessWidget {
RecommendedPlantViewModel recommendedPlantViewModel =
new RecommendedPlantViewModel();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
recommendedPlantViewModel.setWidgetsData();
return SingleChildScrollView(
child: Column(
children: [
HeaderWithSearchBox(size: size),
TitleWithMoreButton(
title: "Recommended",
press: () {},
),
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return Card(
child: ListTile(
onTap: (){},
title: Text('Hello'),
),
);
})
],
),
);
}
}
It doesn't look like there's any other way than setting height constraint using a SizedBox that's wrapping a ListView.
Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: size.height,
child: ListView.builder(
...
),
),
],
)
https://flutter.dev/docs/cookbook/lists/horizontal-list
i think it happened because the list view should have a height,,
the esiest way is to test that put it inside a container and give a height to it..
and the second way is wrap the listview inside a Expanded widget and it will fix ..
if not then post the error from debug log
In order to make this to work, you must wrap your ListView with a Container and define the height property as it is part of a Column. You also need to wrap the widget returned by the itemBuilder with a Container and define the width property as the scrollDirection is set to Axis.horizontal.
Container(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
width: 100,
child: Card(
child: ListTile(
onTap: () {},
title: Text('Hello'),
),
),
);
},
),
)

Expand Widget to fill remaining space in ListView

As in the image shown above, I want widget 2 to always be at least the height of the remaining space available.
But widget 2 might contain so many ListTiles so that they can not be displayed without scrolling. But scrolling should affect widget 1 and widget 2. What is the best way to implement something like this?
Wrap Widget 2 in an Expanded Widget.
To scroll both Widget 1 and Widget 2, wrap both of them in a SingleChildScrollView Widget.
If you can distinguish between the case with a few and many elements (for example during loading), you can use CustomScrollView with SliverFillRemaining for this:
var _isLoading = true;
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
_buildWidget1(),
_buildWidget2(),
],
);
}
Widget _buildWidget1() {
return SliverToBoxAdapter(
child: Container(height: 400, color: Colors.blue),
);
}
Widget _buildWidget2() {
if(_isLoading) {
return SliverFillRemaining(
hasScrollBody: false,
child: Center(child: const CircularProgressIndicator()),
);
} else {
return SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
_buildItem,
childCount: childCount,
),
itemExtent: 56,
);
}
}
A simple way to do that would be to place your widgets in Column and wrap it with a single child scroll view. For the ListView use shrinkWrap as true and physics you can set to NeverScrollableScrollPhysics
Here is an example
SingleChildScrollView(
child: Column(
children: [
Container(
height: MediaQuery.of(context).size.height / 2,
color: Colors.red,
),
ListView.builder(
shrinkWrap:true,
physics:NeverScrollableScrollPhysics(),
itemCount: 100,
itemBuilder: (context, index) => Text("$index"),
),
],
),
);
Hope this helps!
var widgetHeight = MediaQuery.of(context).size.height - fixedSize;
return SingleChildScrollView(
child: Container(
height: widgetHeight,
child: Widget2
)
)

ListView inside Column throws error 'Vertical viewport was given unbounded height'

My question seems to be a duplicate of ListView inside Column causes 'Vertical viewport was given unbounded height' but the solution to add an Expanded or Flexible widget around the ListView doesn't work at all. It still throws the same error: Vertical viewport was given unbounded height.
var data = ['a','b','c','d'];
Column(
children: <Widget>[
ListView.builder(
itemCount: data.length,
itemBuilder: (ctx, i) {
return Row(
children: <Widget>[
Text(data[i], style: TextStyle(fontSize: 24 * Rat.rat, color: Colors.white)),
],
);
},
),
],
);
Obviously it can easily be fixed by adding a container around the ListView with a fixed height but there should be no need for that, I want it to be dynamically sized.
UPDATE:
Try something like this:
class Esempio1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("WAKAWAKA"),
),
body: Container(
child: Column(
children: <Widget>[
Text("eg1"),
Text("eg2"),
Text("eg3"),
Expanded(
child: ListView.builder(
itemCount: 20,
itemBuilder: (ctx,i){
return ListTile(title: Text("aaaaaa$i"),);
},
),
)
],
),
),
);
}
}
I just tried this code and it should do what you want.
The OP actually had the block of code posted contained inside another Column, that's why the Expanded wasn't working as it should when wrapped around the ListView. Wrapping the Column inside another Expanded solved the problem and made it all work as expected.
How about wrapping ListView builder in SingleChildScrollView and setting up its physics to
physics: NeverScrollableScrollPhysics(),

problem SingleChildScrollView with PageView flutter

I want to add SingleChildScrollView in my page but i have PageView.
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new IneatAppBarPollWidget()
.getAppBar('Blackblox', 'assets/img/logo_ineat.png', cand),
body: new Center(
child: SingleChildScrollView(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Expanded(
child: new Container(
child: new FutureBuilder<List<PollQuestionsDto>>(
future: _future,
// ignore: missing_return
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Failed connection API');
case ConnectionState.waiting:
return new Text('Wait...');
case ConnectionState.done:
if (snapshot.hasData) {
if (snapshot.data != null) {
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, index) {
print(this.responses);
return PollListViewItem(
entitled:
snapshot.data[index].entitled,
answers:
snapshot.data[index].answers,
currentAnswer:
this.responses[index],
onSelect: (Answer answer) {
this.responses[index] = answer;
},
);
},
);
}
}
break;
case ConnectionState.active:
}
}),
),
),
new ProgressBar(),
new Container(
margin: EdgeInsets.only(right: 10.0),
child: new RaisedButton.icon(
onPressed: () async {
//await Poll().submitPoll(answers: answers);
setState(() {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) =>
PollPage()));
});
},
label: Text('Suivant'),
icon: Icon(Icons.navigate_next),
),
alignment: Alignment.bottomRight,
),
],
),
),
),
);
}
}
When I added this, I have this error :
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
When a column is in a parent that does not provide a finite height constraint, for example if it is in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the vertical direction.
These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children (using Flexible rather than Expanded). This will allow the flexible children to size themselves to less than the infinite remaining space they would otherwise be forced to take, and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.
RenderBox was not laid out: RenderFlex#4c442 relayoutBoundary=up12 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1681 pos 12: 'hasSize'
I recreated your case with a sample data. Below are the issues that I fixed:
Column used inside SingleChildScrollView expands to fill vertical space by default if we don't set the mainAxisSize for it. So here, you will need to add mainAxisSize: MainAxisSize.min, which tells column to take only the minimum space.
The children to be displayed inside Column were wrapped in Expanded which again takes up default space for its child. Here, instead of Expanded, use Flexible which takes the space as applicable to its child.
The Container used to display the data from future builder again expands to the entire screen if not provided a height. So just provide a custom height to the Container.
Working code below:
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Container(
height: 200,
child: FutureBuilder<Post>(
future: post,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Failed connection API');
case ConnectionState.waiting:
return new Text('Wait...');
case ConnectionState.done:
if (snapshot.hasData) {
if (snapshot.data != null) {
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: 5,
itemBuilder: (BuildContext context, index) {
return Card(
child: Text('test'),
);
},
);
}
}
break;
case ConnectionState.active:
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
)
),
Container(
margin: EdgeInsets.only(right: 10.0),
child: new RaisedButton.icon(
onPressed: () {},
label: Text('Suivant'),
icon: Icon(Icons.navigate_next),
),
alignment: Alignment.bottomRight,
)
],
),
)
),
Based on the sample data I used, I was able to see below result and was able to scroll horizontally to see the data properly.

How to Center SingleChildScrollView but make background stretch to fill screen?

I am use Flutter for web for make website. I want make webpage scroll when user scroll down like normal website.
I am try use Stack so I can place custom background behind widgets. This background must scroll when user scroll (must stick to widgets in front so background change).
(I cannot set background color using Scaffold because my background is use CustomPainter)
But I want center the widgets on webpage, so I wrap SingleChildScrollView in Center widget. But now on large horizontal screen the CustomPaintWidget() is not fill screen (there is blank space). I have try replace my CustomPaintWidget() with Container to test, but same issue.
Here my code:
Center(
child: SingleChildScrollView(
child:Stack(children: <Widget>[
CustomPaintWidget(),
Widgets(),
],),
Anyone know solution?
How to center widgets but also make background stretch?
Thanks!
SingleChildScrollView by definition shriknwraps it's child.
What you should try is
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
//Use MediaQuery.of(context).size.height for max Height
constraints: BoxConstraints(minHeight: MediaQuery.of(context).size.height),
child: Center(
child: //Widget,
),
),
);
I think you can try something like:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
CustomPaintWidget(),
Center(
child: SingleChildScrollView(
child: Widgets(),
),
)
],
));
}
read that post, I think is all you need https://medium.com/#swav.kulinski/spike-parallax-in-flutter-seven-lines-of-code-16a1890d8d32
I know it is too late to answer but s.o may need it in future
You have to use Stack
for instance:
your MainClass:
class _BodyState extends State<Body> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
ScrollViewClass(),
Column(
children: [
//YOUR ITEMS
]),
);
ScrollviewClass:
class ScrollViewClass extends StatefulWidget {
#override
_ScrollViewClassState createState() => _ScrollViewClassState();
}
class _ScrollViewClassState extends State<ScrollViewClass> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.only(top: 260, bottom: 100),
child: ListView(
children: [
Container(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: ConstrainedBox(
//Use MediaQuery.of(context).size.height for max Height
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height),
child: Column(
children: [
//ADD YOUR ITEMS LIKE IMAGE, TEXT, CARD ETC...
Center(child: Image.asset('assets/app_name.png')),
Center(child: Image.asset('assets/app_name.png')),
Center(child: Image.asset('assets/app_name.png')),
Center(child: Image.asset('assets/app_name.png')),
Center(child: Text('fdgdfg')),
Center(child: Text('fdgdfg')),
],
)),
),
)
],
),
));
}
}
I know this is not the OP's scenario, but for others - If there is something above your scroll view, using the full height of the page will cause the scrollview to scroll prematurely, because the combined height of the widgets is now greater than the page height. Use LayoutBuilder instead of MediaQuery.of(context).size.height.
LayoutBuilder(builder: ((context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight),
child: Center(child: child)),
);
})