Flutter A RenderFlex overflowed by X pixels on the right - flutter

I'm learning flutter and dart by creating one of our wpf apps.
However, my DataTable throws exception:
======== Exception caught by rendering library =====================================================
A RenderFlex overflowed by 10.0 pixels on the right.
Did some reasearch and there were options to use Expanded, SingleChildScrollView etc. but still nothing helps.
If I make my data row strings smaller, everything is fine.
Widget code
class WorkList extends StatefulWidget {
WorkListState createState() => new WorkListState();
}
class WorkListState extends State<WorkList> with SingleTickerProviderStateMixin {
List<DataRow> _activities = [
DataRow(
cells: <DataCell>[
DataCell(Text('William')),
DataCell(Text('27')),
DataCell(Text('Associate Professor')),
DataCell(Text('Associate Professor1')),
DataCell(Text('Associate Professor1')),
]
)
];
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
_controller = TabController(length: 2, vsync: this);
_controller.addListener(() {
_filterActivities();
});
}
#override
dispose(){
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
super.dispose();
}
TabBar get _tabBar => TabBar(
labelColor: Colors.white,
controller: _controller,
indicator: BoxDecoration(
color: orangeBackground,
),
tabs: [
Tab(text: 'SHOW CURRENT'),
Tab(text: 'SHOW ALL')
],
);
TabController _controller;
DataTable get _dataTable => DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text(
'First Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Last Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Id',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Time',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Operator',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: _activities,
);
void _filterActivities() {
setState(() {
_dataTable.rows.clear();
_activities.add(
DataRow(
cells: <DataCell>[
DataCell(Text('Some random')),
DataCell(Text('Some random1')),
DataCell(Text('Associate Professor1111111111dasdasds')),
DataCell(Text('Associate Professor1111111adssaa')),
DataCell(Text('TEEEEEEEEEEESTdsdasds')),
]
)
);
});
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: PreferredSize(
preferredSize: _tabBar.preferredSize,
child: ColoredBox(
color: midDarkBackground,
child: _tabBar,
),
),
title: Text('Worklist'),
),
body: Column(
children: <Widget>[
Expanded(
child: TabBarView(
controller: _controller,
physics: NeverScrollableScrollPhysics(), // disable swipe
children: [
_dataTable,
_dataTable
],
),
)
],
),
floatingActionButton: FloatingActionButton.extended(
label: Text('CREATE NEW PROCEDURE'),
backgroundColor: darkBackground,
foregroundColor: Colors.white,
),
),
);
}
}

In case you want to have a horizontal scroll for your table, just wrap the DataTable widget with SingleChildScrollView with scrollDirection: Axis.horizontal.
So your get _dataTable would be the following:
get _dataTable => SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: const <DataColumn>[...],
rows: ...,
),
);
Result:
If you want to have a bidirectional scroll, wrap it with the second SingleChildScrollView like this:
get _dataTable => SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: const <DataColumn>[...],
rows: ...,
),
),
);

Related

How to make a screen with Tabs and TabBarViews both scrollable in flutter?

I've been trying to add SingleChildScrollView to my code so that the whole page including Tabs and TabBarViews are scrolled together.
RenderFlex children have non-zero flex but incoming height constraints are unbounded
Horizontal viewport was given unbounded height.
These are the errors I encountered to make the whole page scrollable.
import 'package:buttons_tabbar/buttons_tabbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import '../widgets/style_grid.dart';
class StyleScreen extends StatefulWidget {
const StyleScreen({super.key});
#override
State<StyleScreen> createState() => _StyleScreenState();
}
class _StyleScreenState extends State<StyleScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Screen')),
body: SafeArea(
child: DefaultTabController(
length: 5,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ButtonsTabBar(
backgroundColor: Colors.grey[300],
radius: 16,
unselectedLabelStyle: TextStyle(color: Colors.black),
labelStyle: TextStyle(
color: Colors.orange, fontWeight: FontWeight.bold),
tabs: [
Tab(
icon: Icon(Icons.directions_car),
text: "All",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat1",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat2",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat3",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat4",
),
],
),
Expanded(
child: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
StyleGrid(),
StyleGrid(),
StyleGrid(),
StyleGrid(),
StyleGrid(),
],
),
),
],
),
),
),
);
}
}
I want to make the red area scrollable.
You can use NestedScrollView. It is better to use ListView.builder or CustomScrollView instead of using SingleChildScrollView on StyleGrid
class StyleScreen extends StatefulWidget {
const StyleScreen({super.key});
#override
State<StyleScreen> createState() => _StyleScreenState();
}
class _StyleScreenState extends State<StyleScreen>
with SingleTickerProviderStateMixin {
late final TabController controller = TabController(length: 5, vsync: this);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Screen')),
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverToBoxAdapter(
child: tabBar(),
)
],
body: TabBarView(
controller: controller,
children: List.generate(
5, (index) => SingleChildScrollView(child: StyleGrid())),
),
),
);
}
ButtonsTabBar tabBar() {
return ButtonsTabBar(
controller: controller,
backgroundColor: Colors.grey[300],
radius: 16,
unselectedLabelStyle: TextStyle(color: Colors.black),
labelStyle: TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
tabs: [
Tab(
icon: Icon(Icons.directions_car),
text: "All",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat1",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat2",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat3",
),
Tab(
icon: Icon(Icons.directions_transit),
text: "Cat4",
),
],
);
}
}
Try wrapping it in the following class. This provides both vertical and horizontal scrolling.
class ScrollableWidget extends StatelessWidget {
final Widget child;
const ScrollableWidget({Key? key, required this.child}) : super(key: key);
#override
Widget build(BuildContext context) => SingleChildScrollView(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: child,
),
);
}

Flutter web - Always show horizontal and vertical scrollbar in a DataTable

I have a DataTable and I'm trying to make it always show the horizontal and vertical scrollbars.
I managed to always show the vertical scrollbar, but the horizontal scrollbar only shows when I scroll down to the bottom.
Here's my code:
final _scrollController = ScrollController();
final _scrollController2 = ScrollController();
#override
Widget build(BuildContext context) {
return Container(
height: 300,
width: 400,
child: Scrollbar(
controller: _scrollController,
isAlwaysShown: true,
child: SingleChildScrollView(
controller: _scrollController,
scrollDirection: Axis.vertical,
child: Scrollbar(
controller: _scrollController2,
isAlwaysShown: true,
child: SingleChildScrollView(
controller: _scrollController2,
scrollDirection: Axis.horizontal,
child: DataTable(
showCheckboxColumn: true,
columns: [
DataColumn(
label: Text('Name'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
],
rows: List<DataRow>.generate(
20,
(int index) => DataRow(
cells: <DataCell>[
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
],
onSelectChanged: (bool? value) {},
),
),
),
),
),
),
),
);
}
I'm using Flutter 2.2.3 (Channel stable).
I tried a lot of things, but I think I finally got it.
here's the final result: Bidirectional scrolling with fixed scrollbar
I used adaptive_scrollbar v2.1.0 to get this result.
Source Code
import 'package:flutter/material.dart';
import 'package:adaptive_scrollbar/adaptive_scrollbar.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Bidirectional Scrollbars',
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) {
final _verticalScrollController = ScrollController();
final _horizontalScrollController = ScrollController();
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: 300,
width: 700,
child: AdaptiveScrollbar(
underColor: Colors.blueGrey.withOpacity(0.3),
sliderDefaultColor: Colors.grey.withOpacity(0.7),
sliderActiveColor: Colors.grey,
controller: _verticalScrollController,
child: AdaptiveScrollbar(
controller: _horizontalScrollController,
position: ScrollbarPosition.bottom,
underColor: Colors.blueGrey.withOpacity(0.3),
sliderDefaultColor: Colors.grey.withOpacity(0.7),
sliderActiveColor: Colors.grey,
child: SingleChildScrollView(
controller: _verticalScrollController,
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
controller: _horizontalScrollController,
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.only(right: 8.0, bottom: 16.0),
child: DataTable(
showCheckboxColumn: true,
columns: [
DataColumn(
label: Text('Name'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Name'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
],
rows: List<DataRow>.generate(
20,
(int index) => DataRow(
cells: <DataCell>[
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
],
onSelectChanged: (bool? value) {},
),
),
),
),
),
),
),
),
),
);
}
}

how to manage textField controller for multiple dataRow in dataTable Flutter

In my flutter project, I want to make the screen which is user enter quantity for multiple product. I want to manage text controllers for multiple data rows in the data table.
My data table code is:
TextEditingController textController = TextEditingController();
AlertDialog(
content: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.height,
margin: EdgeInsets.all(0),
child: ListView(
padding: EdgeInsets.all(0),
primary: true,
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: [
DataTable(
columns: [
DataColumn(
label: Text(
"Product",
softWrap: true,
),
),
DataColumn(
label: Text(
"Qty",
),
),
DataColumn(
label: Text(
"Rs",
)),
DataColumn(
label: SizedBox(
width: 40,
child: Text(
'BalQty',
),
),
),
DataColumn(
label: SizedBox(
width: 40,
child: Text(
'Stock',
),
),
),
],
rows: listOfProduct!
.map(
((element) => DataRow(
cells: <DataCell>[
DataCell(Text(
element.name,
)),
DataCell(
TextField(
controller: textEditingController,
maxLength: 4,
decoration: InputDecoration(
labelText: 'Qty',
labelStyle: TextStyle(fontSize: 9.sp),
counterText: "",
),
),
),
DataCell(
Text(
(element.pTR ?? 0).toStringAsFixed(2),
),
),
DataCell(Text(
element.text!.printDashIfEmpty(),
)),
DataCell(Text(
(element.balQty ?? 0).toStringAsFixed(2),
)),
],
)),
)
.toList(),
),
],
),
),
actions: <Widget>[
OutlinedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Cancel",
)),
SizedBox(
width: 10,
),
OutlinedButton(
onPressed: () async {
print("QUANTITY : $textEditingController");
listSearchProductMaster!.forEach((e) {
return print("TEXT CONTROLLER: ${e.textEditingController}");
});
},
child: Text(
"Add",
))
],
)
The output I see is that the quantity that the user inserts should be added to the particular product.
Currently, my application output is
Does anyone help?
Well, in my case, my approach was:
When user tap item to edit, show modal with initial value
User make input and tab Confirm button
after valid input, apply
It wrap focus node and controller, so easy to use.
But it force user to dig in 1 more UI level, so maybe there are better ways, but it works anyway.
I made TextEditModal widget and function to show that.
Future<String> showSingleTextEditDialog({
#required BuildContext context,
String initText = '',
}) async {
String text = initText;
bool submit = false;
await showDialog(
context: context,
builder: (_) {
return _SingleTextEditDialog(
text: text,
textChanged: (value) => text = value,
onSubmit: () => submit = true,
);
},
);
return submit ? text : null;
}
class _SingleTextEditDialog extends StatefulWidget {
_SingleTextEditDialog({
Key key,
#required this.text,
#required this.textChanged,
this.onSubmit,
}) : super(key: key);
final String text;
final ValueChanged<String> textChanged;
final VoidCallback onSubmit;
#override
_SingleTextEditDialogState createState() => _SingleTextEditDialogState();
}
class _SingleTextEditDialogState extends State<_SingleTextEditDialog> {
TextEditingController textController;
#override
void initState() {
super.initState();
textController = TextEditingController(text: widget.text);
}
#override
void dispose() {
textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SimpleDialog(
children: [
DecoInput(
controller: textController,
onChanged: widget.textChanged,
),
VSpace.md,
StyledInterfaceButton(
onTap: () {
setState(() => widget.onSubmit());
Navigator.of(context).pop();
},
text: 'Confirm',
),
// VSpace.md,
],
);
}
}
and use like
onTap: () async {
HapticFeedback.mediumImpact();
final input = await showSingleTextEditDialog(
context: context,
initText: text,
);
if (input == null) return;
// valid user input here
valueChanged(input); // apply user input
},
This is not complete code. I minimized code for readability. So ignore if there are any error.
Add your table code inside SingleChildScrollView() with scrollDirection: Axis.horizontal refer below code hope it help to you
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(20),
child: Table(
defaultColumnWidth: FixedColumnWidth(80.0),
border: TableBorder.all(
color: Colors.black,
style: BorderStyle.solid,
width: 2),
children: [
TableRow(
children: [
Column(
children: [
Text(
'Website',
style: TextStyle(fontSize: 20.0),
),
],
),
Column(
children: [
Text(
'Tutorial',
style: TextStyle(fontSize: 20.0),
),
],
),
Column(
children: [
Text(
'Review',
style: TextStyle(fontSize: 20.0),
),
],
),
Column(children: [
Text(
'Review',
style: TextStyle(fontSize: 20.0),
),
]),
Column(
children: [
Text(
'Review',
style: TextStyle(fontSize: 20.0),
),
],
),
],
),
TableRow(children: [
Column(
children: [
Text('Javatpoint'),
],
),
Column(
children: [
Text('Flutter'),
],
),
Column(
children: [
Text('5*'),
],
),
Column(
children: [
Text('5*'),
],
),
Column(
children: [
Text('5*'),
],
),
]),
TableRow(
children: [
Column(children: [
Text('Javatpoint'),
]),
Column(
children: [
Text('MySQL'),
],
),
Column(
children: [
Text('5*'),
],
),
Column(children: [
Text('5*'),
]),
Column(children: [
Text('5*'),
]),
],
),
],
),
),
],
),
),
Scroll your table horizontaly
Your screen like - >

Attaching horizontal and vertical scrollbar to the same widget

I want to create a viewport that could be horizontally and vertically scrolled. I am able to achieve this by using two nested SingleScrollChildView. The problem is that the horizontal scrollbar is not attached to the viewport as desired but rather it is attached/present at the bottom vertically which is expected. Is there a way to achieve such a behavior? Please be gentle as I am still learning this framework. Here is the code snippet:
Scrollbar(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Scrollbar(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: CustomViewPort(),
),
),
),
),
Like this?
Bidirectional scrolling with fixed scrollbar
I used adaptive_scrollbar v2.1.0 to get this result.
Source Code
import 'package:flutter/material.dart';
import 'package:adaptive_scrollbar/adaptive_scrollbar.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Bidirectional Scrollbars',
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) {
final _verticalScrollController = ScrollController();
final _horizontalScrollController = ScrollController();
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: 300,
width: 700,
child: AdaptiveScrollbar(
underColor: Colors.blueGrey.withOpacity(0.3),
sliderDefaultColor: Colors.grey.withOpacity(0.7),
sliderActiveColor: Colors.grey,
controller: _verticalScrollController,
child: AdaptiveScrollbar(
controller: _horizontalScrollController,
position: ScrollbarPosition.bottom,
underColor: Colors.blueGrey.withOpacity(0.3),
sliderDefaultColor: Colors.grey.withOpacity(0.7),
sliderActiveColor: Colors.grey,
child: SingleChildScrollView(
controller: _verticalScrollController,
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
controller: _horizontalScrollController,
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.only(right: 8.0, bottom: 16.0),
child: DataTable(
showCheckboxColumn: true,
columns: [
DataColumn(
label: Text('Name'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Name'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
],
rows: List<DataRow>.generate(
20,
(int index) => DataRow(
cells: <DataCell>[
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
],
onSelectChanged: (bool? value) {},
),
),
),
),
),
),
),
),
),
);
}
}

Make DataTable Scroll Bidirectional in Flutter

How to make DataTable Scroll Bidirectional.
I made the datatable scroll Horizontally but my list is large and unable to scroll down.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Bills Receivable"),),
body:SingleChildScrollView(
scrollDirection: Axis.horizontal,
child:
DataTable(
columns: <DataColumn>[
DataColumn(label:Text("BNm",style: TextStyle(fontWeight: FontWeight.bold),)),
DataColumn(label:Text("BDt",style: TextStyle(fontWeight: FontWeight.bold),)),
DataColumn(label:Text("BPrty",style: TextStyle(fontWeight: FontWeight.bold),)),
DataColumn(label:Text("BdueDt",style: TextStyle(fontWeight: FontWeight.bold),)),
DataColumn(label:Text("Dys",style: TextStyle(fontWeight: FontWeight.bold),)),
DataColumn(label:Text("BAmt",style: TextStyle(fontWeight: FontWeight.bold),)),
DataColumn(label:Text("BPAmt",style: TextStyle(fontWeight: FontWeight.bold),)),
DataColumn(label:Text("BBAmt",style: TextStyle(fontWeight: FontWeight.bold),))
], rows: widget.rdata.bRecDtl.map((e)=>
DataRow(
cells:<DataCell>[
DataCell(Text(e.bNm.toString())),
DataCell(Text(e.bDt.toString())),
DataCell(Text(e.bPrty.toString())),
DataCell(Text(e.bdueDt.toString())),
DataCell(Text(e.dys.toString())),
DataCell(Text(e.bAmt.toString())),
DataCell(Text(e.bPAmt.toString())),
DataCell(Text(e.bBAmt.toString())),
])).toList()
),
),
);
}
Just add two SingleChildScrollViews:
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable()
Newer and easier way.
As of the most recent Flutter update, you can also wrap your DataTable in an InteractiveViewer widget with the constrained property set to false. Unlike earlier solutions, this will allow you to scroll both horizontally and vertically at the same time. It is also less code and lets you zoom in/out of your DataTable.
Good luck!
If anyone here is using a PaginatedDataTable or PaginatedDataTable2, you need to set the minWidth property in order to get the horizontal scroll working.
You can use two SingleChildScrollView or one InteractiveViewer.
But if you want two fixed scrollbars like this.
Bidirectional scrolling with fixed scrollbar
I used two SingleChildScrollView and adaptive_scrollbar v2.1.0 to get this result.
Source Code
import 'package:flutter/material.dart';
import 'package:adaptive_scrollbar/adaptive_scrollbar.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Bidirectional Scrollbars',
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) {
final _verticalScrollController = ScrollController();
final _horizontalScrollController = ScrollController();
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: 300,
width: 700,
child: AdaptiveScrollbar(
underColor: Colors.blueGrey.withOpacity(0.3),
sliderDefaultColor: Colors.grey.withOpacity(0.7),
sliderActiveColor: Colors.grey,
controller: _verticalScrollController,
child: AdaptiveScrollbar(
controller: _horizontalScrollController,
position: ScrollbarPosition.bottom,
underColor: Colors.blueGrey.withOpacity(0.3),
sliderDefaultColor: Colors.grey.withOpacity(0.7),
sliderActiveColor: Colors.grey,
child: SingleChildScrollView(
controller: _verticalScrollController,
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
controller: _horizontalScrollController,
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.only(right: 8.0, bottom: 16.0),
child: DataTable(
showCheckboxColumn: true,
columns: [
DataColumn(
label: Text('Name'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Name'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
DataColumn(
label: Text('Year'),
),
],
rows: List<DataRow>.generate(
20,
(int index) => DataRow(
cells: <DataCell>[
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
DataCell(
Text('Row $index'),
),
],
onSelectChanged: (bool? value) {},
),
),
),
),
),
),
),
),
),
);
}
}
I used to code this way, and it works fine:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:followmeifucan/constants/style_constants.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class RankScreen extends StatefulWidget {
static String id = 'ranks_screen';
#override
_RankScreenState createState() => _RankScreenState();
}
class _RankScreenState extends State<RankScreen> {
final _firestore = Firestore.instance;
#override
void initState() {
super.initState();
}
List<DataCell> _createCellsForElement(DocumentSnapshot document){
Timestamp timestamp = document.data['when'];
return <DataCell>[
DataCell(Text(document.data['name'].toString())),
DataCell(Text(document.data['level'].toString())),
DataCell(Text(document.data['round'].toString())),
DataCell(Text(document.data['hits_ok'].toString())),
DataCell(Text(timestamp.toDate().toString().substring(0, 16))),
DataCell(Icon(document.data['plataform'].toString() == 'Android' ? Icons.android : FontAwesomeIcons.apple))
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.black,
title: Row(
children: <Widget>[
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 30.0,
child: Image.asset('images/default_icon.png'),
),
),
),
SizedBox(width: 10.0,),
Text('HIGHSOCRES'),
],
),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('ranks').snapshots(),
builder: (context, snapshot){
List<DataRow> rankLines = new List<DataRow>();
if(snapshot.hasData){
final ranks = snapshot.data.documents;
for(var rankData in ranks){
rankLines.add(
DataRow(
cells: _createCellsForElement(rankData)
)
);
}
}
return Container(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
sortAscending: true,
sortColumnIndex: 3,
columns: <DataColumn>[
DataColumn(label: Text('NAME', style: kRankLabelStyle,)),
DataColumn(label:Text('LEVEL', style: kRankLabelStyle,), numeric: true,),
DataColumn(label:Text('ROUND', style: kRankLabelStyle,), numeric: true,),
DataColumn(label:Text('HITS OK', style: kRankLabelStyle,), numeric: true,),
DataColumn(label:Text('WHEN', style: kRankLabelStyle,),),
DataColumn(label:Icon(Icons.phone_iphone)),
],
rows: rankLines,
),
),
);
},
),
]
),
),
),
),
);
}
}
I published this package for bidirectional tables: easy_table
Try this:
SingleChildScrollView(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: ...,
),