I'm trying to build a Data Table variant so that the row can be expanded with extra information. I didn't found a way to do this with the DataTable class.
This is what I have:
class TestPanel extends StatefulWidget {
const TestPanel({Key? key}) : super(key: key);
#override
_TestPanelState createState() => _TestPanelState();
}
class _TestPanelState extends State<TestPanel> {
bool _customTileExpanded = false;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: const <Widget>[
Expanded(
child: Text("Header 1"),
),
Expanded(
child: Text("Some Header 2"),
),
Expanded(
child: Text(""),
)
],
),
),
Expanded(
child: ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return ExpansionPanelList(
animationDuration: Duration(milliseconds: 1000),
dividerColor: Colors.grey,
elevation: 1,
children: [
ExpansionPanel(
body: Container(
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Some text here",
style: TextStyle(
color: Colors.grey[700],
fontSize: 15,
letterSpacing: 0.3,
height: 1.3),
),
],
),
),
headerBuilder: (BuildContext context, bool isExpanded) {
return Container(
padding: EdgeInsets.all(10),
child: Row(
children: const <Widget>[
Expanded(
child: Text("Value 1"),
),
Expanded(
child: Text("Some Value 2"),
),
],
),
);
},
isExpanded: _customTileExpanded,
)
],
expansionCallback: (int item, bool expanded) {
setState(() => _customTileExpanded = !expanded);
},
);
},
),
),
],
),
);
}
}
Now this results in:
As you can see the alignment with the headers is not correct. I have no idea how I can make sure that those are always aligned.
There's a tricky solution here by adding SizedBox with the same width of the ExpansionPanelList icon "including it's padding" at the end of the header row like following:
Row(
children: [
Expanded(
child: Row(
children: const <Widget>[
Expanded(
child: Text("Header 1"),
),
Expanded(
child: Text("Some Header 2"),
),
],
),
),
// If the Header text "Some Header 2" is longer than the Expansion Header "Some Value 2" you'll need to increase the Sizedbox width.
const SizedBox(
64, //ExpansionPanelList IconContainer size: end margin 8 + padding 16*2 + size 24
),
],
),
Also, I dont' know if this would work with your idea but you can have dynamic rows height with DataTable2 Package but first you need to copy the package code and paste it in your root directory of your current project to make some edits on it "To make the row's height dynamic":
For having Dynamic row height remove height: effectiveDataRowHeight and height: effectiveHeadingRowHeight from the new widget file.
You can add constraints: BoxConstraints(minHeight: effectiveHeadingRowHeight,) and constraints: BoxConstraints(minHeight: effectiveDataRowHeight,) instead of above and use dataRowHeight parameter as min Height and same for headingRowHeight.
To center all data in cells add defaultVerticalAlignment: TableCellVerticalAlignment.middle to var dataRows in the widget code.
Result:
Image
You can also do the same with the DataTable class but at step3, You need to add defaultVerticalAlignment: TableCellVerticalAlignment.middle to the Table child in the image: Image
I prefer using DataTable2 as it has more customization, you can find it here: DataTable2
After That, You can add Icon at the end of the row. If it's clicked you add new row with extra information.
Related
I want the cards built in a listview.builder, to have a height of 150.
What currently happens:
Currently, with my code, here's what gets built. Instead of the default height, I want to explicitly set my own card height, say, 150
What I have tried:
Isn't using SizedBox enough to get the height I want in a listview?
class GamesListState extends State<GamesList> {
#override
Widget build(BuildContext context) {
return MyScaffold(
body: Container(
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 32),
const MyHeaderTitle(title: 'Games'),
const SizedBox(height: 40),
Flexible(
child: ListView.builder(
itemCount: list.length,
prototypeItem: ListTile(
title: Text(list.first.values.first),
),
itemBuilder: (context, index) {
return Card(
elevation: 5,
child: SizedBox(
height: 150,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset('assets/images/logo.png'),
const Text(
'Game name',
style: TextStyle(
fontSize: 10, fontWeight: FontWeight.w700),
),
const Icon(Icons.keyboard_arrow_right)
],
),
),
);
},
)),
],
),
),
);
}
}
Will appreciate any insights as to what I'm doing wrong.
Specify the height of prototypeItem of listView.builder by wrapping it with SizedBox
prototypeItem: ListTile(
title: SizedBox(height: 150, child: Text(list.first.values.first)),
),
Need help. I have created a column on the page inside which there are 2 more columns, so I moved the buttons that are at the bottom to the very bottom so that they are always at the bottom of the screen. But when I add a SingleChildScrollView to make the page scroll, the space between the columns disappears and the bottom buttons move under other widgets. How can I solve the problem so that when adding a SingleChildScrollView, there is an empty space and the buttons remain at the very bottom of the screen?
body
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
const SizedBox(height: 121.0),
BackStepWidget(
text: 'Balance: $coins',
textStyle: constants.Styles.largeHeavyTextStyleWhite,
),
const Text(
'Buy JoinCoins',
style: constants.Styles.bigHeavyTextStyleWhite,
),
const Image(
image: AssetImage('assets/images/image.png'),
),
const Text('I Want To Buy',
style: constants.Styles.smallBoldTextStyleWhite),
const SizedBox(height: 10),
const CoinsCounterWidget(),
const SizedBox(height: 10),
const Text('JoynCoins',
style: constants.Styles.smallBoldTextStyleWhite),
],
),
Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 24),
child: DefaultButtonGlow(
text: 'Buy me JoynCoins for 100% battery.',
color: constants.Colors.greyLight.withOpacity(0.4),
textStyle: constants.Styles.buttonTextStyle,
shadowColor: Colors.transparent,
borderColor: constants.Colors.purpleMain,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return const DefaultAlertDialog(
text:
'Please set a payment method for buying JoynCoins.',
);
},
);
},
),
),
Padding(
padding: const EdgeInsets.only(bottom: 47),
child: DefaultButtonGlow(
text: 'Buy Now ',
color: constants.Colors.purpleMain,
textStyle: constants.Styles.buttonTextStyle,
shadowColor: constants.Colors.purpleMain,
borderColor: constants.Colors.purpleMain,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return const DefaultAlertDialog(
text: "You'r about to buy",
isText2: true,
text2: '2500 JoynCoins',
);
});
},
),
)
],
)
],
),
));
Added SingleChildScrollView
Without SingleChildScrollView
You can simplify this code to understand the issue. MainAxisAlignment.spaceBetween will provide maximum spaces between widgets.
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("top"),
Text("bottom"),
],
),
Once you wrapped with SingleChildScrollView, Column takes minimum height for its children and become,
You can use SizedBox to provide space between items. You can use LayoutBuidler that I've posted on your previous question. For this I am using MediaQuery
body: SingleChildScrollView(
child: Column(
children: [
Text("top"),
SizedBox(
height: MediaQuery.of(context).size.height * .4,
), // you custom height
Text("bottom"),
],
),
),
Use SizedBox in between Columns or use the following inside Singlechildscrollview
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
I can't work this out. It should be really simple. (This is Flutter Desktop)
I want a Row with 2 columns. The first column should be full height available but only 200 wide. Column 2 should be full height and use the remainder of the width.
I have tried all sorts but always get an overflow rather than a scrollable list.
What am I doing wrong?
This is the last iteration of my code.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bnode Management'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('This is the title'),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
width: 200,
child: ListView.builder(
shrinkWrap: true,
itemCount: piItems.length,
itemBuilder: (BuildContext context, int index) {
return Container(width: 40, color: Colors.red, child: Text(piItems[index].id));
}),
),
),
Container(color: Colors.blue, child: const Text('Column 1')),
],
),
],
),
);
}
}
The second Column like to have max space, therefor we can use Expanded on it instead of using on 1st Column. Also, the Row is needed to have max height. For this, we will wrap this Row with Expanded.
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('This is the title'),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 200,
child: ListView.builder(
shrinkWrap: true,
itemCount: piItems.length,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 40,
color: Colors.red,
child: Text(piItems[index].id));
}),
),
Expanded(
child: Container(
color: Colors.blue,
child: Column(
children: [
const Text('Column 1'),
],
),
),
)
],
),
),
],
),
I also prefer using LayoutBuilder on body in this case.
You almost got it right, just mixed some things. Let's go step by step.
I want a Row with 2 columns
Ok, that's just a Row with two children.
Row(
children: [child1, child2],
)
The first column should be full height available but only 200 wide.
It would take the full height automatically but I see that in your code example you have a Column with Text title, so we should wrap our Row with Expanded. Also, the first Column should take 200 px.
Column(
children: [
const Text('This is the title'),
Expanded(
child: Row(
children: [
Container(
width: 200,
child: child1,
),
child2,
],
),
),
],
)
Column 2 should be full height and use the remainder of the width.
So we wrap our 2nd child with Expanded inside the Row.
Column(
children: [
const Text('This is the title'),
Expanded(
child: Row(
children: [
Container(
width: 200,
child: child1,
),
Expanded(
child: child2,
),
],
),
),
],
)
The end result based on your code:
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bnode Management'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('This is the title'),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 200,
child: ListView.builder(
shrinkWrap: true,
itemCount: piItems.length,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 40,
color: Colors.red,
child: Text(piItems[index].id));
},
),
),
Expanded(
child: Container(
color: Colors.blue,
child: const Text('Column 1'),
),
),
],
),
),
],
),
);
}
}
My layout is a Form widget with some controls:
Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Form(
key: widget.addEventFormKey,
onChanged: () {},
child: Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(CustomResources.strings["add_event_category_label"], style: TextStyle(fontWeight: FontWeight.bold)),
/*some other widgets*/
Visibility(
child: Container(
height: 200.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _attachments?.length,
itemBuilder: (context, index) {
return Stack(
children: [
Container(
margin: EdgeInsets.fromLTRB(0, 0, 5, 0),
child: Stack(
children: [
ClipRRect(
child: Image.file(File(_attachments[index]), cacheWidth: 200),
borderRadius: BorderRadius.circular(8.0),
),
],
),
),
IconButton(
onPressed: () {
File(_attachments[index]).delete();
setState(() => _attachments.remove(_attachments[index]));
},
icon: Icon(FontAwesomeIcons.trash, color: Colors.white, size: 20),
padding: EdgeInsets.only(top: 4, left: 4),
constraints: BoxConstraints(),
),
],
);
},
),
),
visible: _attachments.length > 0,
),
Visibility(child: Padding(padding: EdgeInsets.fromLTRB(0, 18, 0, 0)),visible: _attachments.length > 0),
SizedBox(
child: RaisedButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24.0)),
onPressed: _attachments.length < 3 ? () => _pickImage() : null,
padding: EdgeInsets.all(12.0),
color: Colors.blue,
child: Text(CustomResources.strings["add_event_add_photo_button_label"], style: TextStyle(color: Colors.white))),
width: double.infinity,
),
],
),
),
),
),
],
);
Problematic part is ListView.builder to display horizontally scrolled list of images. As you can see, picture will always get fixed width (200) and unknown height, because height depends from image aspect ratio. ListView.builder is wrapped with Container, so now it has constant height 200.
I want to force my ListView.builder to expand to child image height (it's single row ListView scrolled horizontally), image width always 200 and other widgets should be placed below it without any remaining space. With current approach, if image height is < 200, there will be remaining space left below image list. If image height is >200, image will be scaled (width/height).
I tried to wrap list view with Expanded widget instead Container, but it throws exception:
RenderFlex children have non-zero flex but incoming height constraints
are unbounded.
It says I still need to provide height, which I don't want to. How to solve this?
I think that's not possible with ListView.builder, because its height with dynamic items is not known while building widgets tree. Instead, my thumbnail widgets mus be built upfront, and added to Row after they have been built and wrap row with SingleChildScrollView to make it scrollable. So, my thumbnails list ready to place to my Form:
class AttachmentsListWidget extends StatelessWidget {
const AttachmentsListWidget({
Key key,
#required this.items,
#required this.onAttachmentDeleted,
}) : super(key: key);
final List<String> items;
final Function(String) onAttachmentDeleted;
#override
Widget build(BuildContext context) {
var _thumbnailsScrollController = ScrollController();
final thumbnails = <Widget>[];
Widget thumbnailsWidget;
if (items.length > 0) {
for (int i = 0; i < items.length; i++) {
thumbnails.add(
AttachmentWidget(
attachment: items[i],
onDeleteClicked: (String attachment) => onAttachmentDeleted(attachment),
),
);
}
thumbnailsWidget = Container(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Scrollbar(
isAlwaysShown: true,
controller: _thumbnailsScrollController,
child: SingleChildScrollView(
controller: _thumbnailsScrollController,
scrollDirection: Axis.horizontal,
child: Row(
children: thumbnails,
crossAxisAlignment: CrossAxisAlignment.start,
),
),
),
],
),
);
} else {
thumbnailsWidget = Container();
}
return thumbnailsWidget;
}
}
(also, always visible scrollbar added).
If you got RenderFlex children have non-zero flex but incoming height constraints are unbounded. try below code hope its help to you. add your Column inside Expanded() Widget and remove SingleChildScrollView() in your code
Expanded(
child: Column(
children:[
//Your Widgets
],
),
),
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class TabStories extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = 'Grid List';
return ListView(
children: List.generate(100, (index) {
return Card(
child: Row(
children: <Widget>[
Flexible(
child: Container(
width: 80,
height: 80,
),
),
Flexible(
child: Text(
'hi i am sfbskdbvkjsdk ksfkj sd hsdvm d dsj s bjksdvjd '),
)
],
),
elevation: 5,
);
}),
);
}
}
dont want the empty space at the end of each row. kindly help
Trying to generate a row with a container containing the image and then a text description of the same. However, getting the empty space at the end.
ListView(
shrinkWrap: true,
children: List.generate(5, (index) {
return Card(
child: Row(
children: <Widget>[
Container(
width: 100,
height: 100,
),
Flexible(
child: Text(
'hi i am sfbskdbvkjsdk ksfkj sd hsdvm d dsj s bjksdvjd ',
style: TextStyle(fontSize: 17),),
)
],
),
elevation: 5,
);
}),
),