Totally I need a scrollable DataTable with refresh possibility on pull down between header and footer fixed width widgets.
I have a widget, using on every page in my app. THis widget return a Scaffold with appbar and body like column (). This widget used like CommonPage(title, widgetsArrayForBodyColumn) from other widgets.
For now I need to use a follow widgets in that body:
Lookup (for filtering or for example, any fixed height widget)
DataTable (for show data)
Card (to show another data)
DataTable should be scrollable and refreshable on pull down.
I tried many different ways, but still has no success. My last solution is using stack, but list hidden beside the card.
I can't understand how to achieve my goal: have refreshing datatable between non scrollable widgets in a column.
class CommonPage extends StatefulWidget {
final String title;
final List<Widget> children;
const CommonPage({
Key? key,
required this.title,
required this.children,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
...
body: Column(children: [
FixedHeightWidget(),
PageScreen(),
]);
}
}
class PageScreen {
#override
Widget build(BuildContext context) {
return CommonPage(
title: Title,
children: [
FixedHeightWidget(),
PageList(),
],
);
}
}
class PageList {
Widget build(BuildContext context) {
//TODO Return fixedWidthWidget at top, expandedRefreshableScrollableDataTable, fixedWidthWidget at bottom
}
}
My current solution: (almost achieves my goal, but as mentioned card hides part of list and no ways to scroll and check bottom of the list):
return Expanded(
child: Stack(
children: [
RefreshIndicator(
onRefresh: onRefresh,
child: ListView(
children: [
listItems.isNotEmpty
? DataTable(...)
: Container(),
],
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
alignment: Alignment.bottomCenter,
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 5),
child: Card(...),
),
),
),
],
),
],
),
);
I found the solution:
return Expanded(
child: Column(
children: [
Expanded(
child: RefreshIndicator(
onRefresh: onRefresh,
child: ListView(
children: [listItems.isNotEmpty
? DataTable(...)
: Container(),
],
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5),
child: Card(...),
),
],
),
);
Related
I have a StatelessWidget defined as:
class FlexElement extends StatelessWidget {
final List<Widget> widgets;
final bool isVisible;
const FlexElement({
Key? key,
required this.widgets,
required this.isVisible,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Visibility(
visible: isVisible,
child: Container(
child: Row(
children: <Widget>[...widgets],
),
),
);
}
}
I would like to wrap each widget with a Flexible, so it doesn't overflow. (Row(children: Flexible([...widgets])). But since it is a list of widgets, I can only assign to multiple children and not to a single child. How would I solve this?
This is the result i would like:
Row(
children: [
Flexible(
child: Widget1(), // <-- Wrapped in Flexible.
),
Flexible(
child: Widget2(), // <-- Wrapped in Flexible.
),
...
],
)
You can do,
children: <Widget>[...widgets.map((w)=>Flexible(child:w))],
Or direct
children:widgets.map((w)=>Flexible(child:w)).toList(),
This is what I always do:
Row(
children: [
Flexible(
flex: 20,
fit: FlexFit.tight,
child: Widget1(), // <-- Wrapped in Flexible.
),
Flexible(
flex: 30,
fit: FlexFit.tight,
child: Widget2(), // <-- Wrapped in Flexible.
),
...
],
)
I put the flex values to total 100 so I think of each as a percentage of the width of the Row.
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.
If I want to add more buttons and text widgets where and how should I do it, should I make some sort of column and row system or am I totally off? And is my code programmed wrong?
import 'package:flutter/material.dart';
void main() {
runApp(
const HomeScreen(),
);
}
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Dice'),
centerTitle: true,
),
body: const Dice()));
}
}
class Dice extends StatefulWidget {
const Dice({Key? key}) : super(key: key);
#override
State<Dice> createState() => _DiceState();
}
class _DiceState extends State<Dice> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/1.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/2.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/3.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/4.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/5.png')))
],
),
));
}
}
I am going to add variables to the children in the container later.
For better understanding I would recommend you checking out this medium article. https://medium.com/flutter-community/flutter-layout-cheat-sheet-5363348d037e Here you can view all the important layout widgets you can use.
In general you have a widget tree starting by MaterialApp and you can add as many items as you want. In flutter if you want multiple widgets you can use Row and Column for that. Both of them provides a children property in brackets [] there you can add multiple widgets inside separated by comma.
Most of the other widgets are also able to provide a children property where you can add even more children widgets. That's how the widget tree in general works. Actually you have unlimited possibility’s.
Your code is totally fine. By the way you can also create custom widgets if the plenty widgets of flutter doesn't fit your use case.
In your example you can add whatever you want in your row, text, more images, buttons, everything you like.
Here you can check out the official widget catalog of flutter: https://docs.flutter.dev/development/ui/widgets
You can place a Column/ListView in between your Center and Row widgets, then you could add multiple rows to it like below:
class _DiceState extends State<Dice> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/1.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/2.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/3.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/4.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/5.png')))
],
),
Row(children: [/* more content here */]),
],
),
),
);
}
}
I am trying to use spacer inside a column that is wrapped with singlechildscrollview and it gives me an error.
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
here is my widget
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Form(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(),
TextFormField(),
//Spacer()
Divider(),
Icon(Icons.block)
],
),
));
}
}
what should i use? your help is appreciated
You can try this out, I added an example using your code, it works:
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(body: LayoutBuilder(
builder: (context, constraint) {
return Form(
child: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
TextFormField(),
TextFormField(),
Spacer(),
Divider(),
Icon(Icons.block)
],
),
),
),
),
);
},
));
}
}
Check this Github issue for much details on the solution above: Wrapping a Column with an expanded in a SingleChildScrollView throws an exception
I want my image to fill exactly half of my screen, and in the bottom row i want to add some more widgets. I tried to make the rows spaceAround so that equal space is given. On adding image widget to row, small image was displayed. I added a SizedBox.expand parent to the image and gave the image BoxFit.fill fit, and then the entire image disappeared all together. How do I fix this problem?
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context){
final view = Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Row(
children: <Widget>[
SizedBox.expand(
child: Image.asset('assets/airb.jpeg'),
)
],
),
Row(
children: <Widget>[
],
)
],
);
return Scaffold(
appBar: AppBar(
title: Text('Image')
),
body: view,
);
}
}
If I got it right, from your description, you would like to have an image on the top half of your screen and then some other widgets below it.
Usually when I do things relative to the size of a container (or relative to the screen size), I'm using LayoutBuilder which will tell you the size constraints that it has (like maxHeight, maxWidth). One thing tho, be careful with it because sometimes these constraints can be =infinity (if you wrap the LayoutBuilder inside a ```Row/Column``
Now for your case you can use the following code snippet:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: LayoutBuilder(builder: (context, constraints) {
return Column(
children: <Widget>[
Container(height: constraints.maxHeight / 2, color: Colors.red), // replace this with an image
//Add extra widgets here.
Text("this will be below image")
],
);
}));
}
Note, the code is a simple example on how to do the sizing, you will have to add the widgets that you need and customise them :).
This may help you-
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
final view = Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
flex: 5,
child: Row(
children: <Widget>[
new Image.asset(
"images/pitch.png",
fit: BoxFit.cover,
),
],
)),
Expanded(
flex: 5,
child: Row(
children: <Widget>[],
)),
],
);
return Scaffold(
appBar: AppBar(title: Text('Image')),
body: view,
);
}
}