I have a layout made of a Column, one of its elements being a row (so that it takes the full width of the screen). Inside that row, I have a wrap, which content is pretty big and that I want to put inside a SingleChildScrollView.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.all(kPaddingMainContainer),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Title', style: Theme.of(context).textTheme.title)
],
),
Padding(
padding: const EdgeInsets.only(top: 10),
),
Row(
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Wrap(
alignment: WrapAlignment.center,
runSpacing: 20.0, // distance between rows
spacing: 30.0, // distance between chips
children: _getWidgets(),
),
),
),
],
),
],
),
),
),
);
}
With this code, I can't get the SingleChildScrollView to make the wrap scrollable. Instead, I got a RenderFlex overflowed error.
However, if I extract the wrap from the Row, as follow:
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.all(kPaddingMainContainer),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Title', style: Theme.of(context).textTheme.title)
],
),
Padding(
padding: const EdgeInsets.only(top: 10),
),
Expanded(
child: SingleChildScrollView(
child: Wrap(
alignment: WrapAlignment.center,
runSpacing: 20.0, // distance between rows
spacing: 30.0, // distance between chips
children: _getWidgets(),
),
),
),
]),
),
),
);
}
Then, the scroll is working.
However, now the wrap doesn't expand to full width anymore, what I want.
How to use the SingleChildScrollView inside a Row ?
PS: I don't want to wrap the Column in a SingleChildScrollView as I want my title to stay fixed and only the wrap below to scroll.
I found a solution by wrapping the Wrap in a ConstrainedBox (instead of a row) for which the minWidth is the width of the screen.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.all(kPaddingMainContainer),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Title', style: Theme.of(context).textTheme.title)
],
),
Padding(
padding: const EdgeInsets.only(top: 10),
),
Expanded(
child: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width,
),
child: Wrap(
alignment: WrapAlignment.center,
runSpacing: 20.0, // distance between rows
spacing: 30.0, // distance between chips
children: _getWidgets(),
),
),
),
),
]),
),
),
);
}
This fixed my issue and I can now scroll the Wrap widget only by tapping anywhere on the screen, while the first row with the title stays fixed.
Related
I'm trying to align 3 widgets inside a Row() evenly.
Just it is not working out as I need it to.
I really do not know how to fix this as I have been at it for hours.
I'm sure thet I'm missing something here.
I'm adding my code and a screenshot of current result.
Updated code!
The issue now seems to couse an out of bounds
New Screenshot
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: rowWidth * 0.2,
alignment: Alignment.centerLeft,
child: CircleAvatar(
backgroundColor: randomColor,
child: Text('JD'),
),
),
Container(
width: rowWidth * 0.2,
alignment: Alignment.centerLeft,
child: Text(
'John Doe',
style:
Theme.of(context).textTheme.subtitle1,
),
),
Container(
width: rowWidth * 0.6,
alignment: Alignment.centerRight,
child: Text(
'Online',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(
color:Theme.of(context).primaryColor,
),
),
),
],
),
],
),
],
),
),
There are a few ways to do it. I modified your Code a bit so you can see it. Your Approach so far was completely fine, you just had to set a width for your Container. Otherwise Flutter doesn't know how to space the elements in the row. Alternatively you could just calculate the width of your Row, and get the width for the Children from that.
I would also recommend putting your Widgets in the Row into Containers for easier handling (like I did below). Hope it helps! Good luck.
Widget _buildTester() {
final fullWidth = MediaQuery.of(context).size.width;
final rowWidth = fullWidth * 0.9; //90%
final containerWidth =
rowWidth / 3; //Could also use this to set the containers individually
return Container(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
width: rowWidth,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
color: Colors.grey,
child: CircleAvatar(
backgroundColor: Colors.red,
child: Text('JD'),
),
),
Container(
color: Colors.green,
child: Text(
'John Doe',
style: Theme.of(context).textTheme.subtitle1,
),
),
Container(
color: Colors.yellow,
child: Text(
'Online',
style: Theme.of(context).textTheme.headline6.copyWith(
color: Theme.of(context).primaryColor,
),
),
),
],
),
],
),
),
],
),
),
);
}
EDIT:
If you want to position your different Elements more freely, I would give the Containers with your Text/Icon in them a fixed width (Calculated from your Row width) and then you can use the Containers 'alignment' property.
In this example I give the green and grey Containers each 20% of the Row and make their content align to the left, and the yellow Container 60% and align it's content to the right.
Widget _buildTester() {
final fullWidth = MediaQuery.of(context).size.width;
final rowWidth = fullWidth * 0.9; //90%
final containerWidth =
rowWidth / 3; //Could also use this to set the containers individually
return Container(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
width: rowWidth,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
width: rowWidth * 0.2,
alignment: Alignment.centerLeft,
color: Colors.grey,
child: CircleAvatar(
backgroundColor: Colors.red,
child: Text('JD'),
),
),
Container(
width: rowWidth * 0.2,
alignment: Alignment.centerLeft,
color: Colors.green,
child: Text(
'John Doe',
style: Theme.of(context).textTheme.subtitle1,
),
),
Container(
width: rowWidth * 0.6,
alignment: Alignment.centerRight,
color: Colors.yellow,
child: Text(
'Online',
style: Theme.of(context).textTheme.headline6.copyWith(
color: Theme.of(context).primaryColor,
),
),
),
],
),
],
),
),
],
),
),
);
}
Simple, do like this.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton(
onPressed: () {},
color: Colors.blue,
child: Text('One'),
),
RaisedButton(
onPressed: () {},
child: Text('Two'),
),
RaisedButton(
onPressed: () {},
child: Text('Three'),
)
],
),
I have an issue in ROW that one child has many items so it is large and another child has fewer items so its height is small so the less item is showing in the center of the ROW, so I need it to align to the top inside the ROW, you can have a look at the image.
Please have a look at my code as well.
rowList = Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: mainBodyList,
);
MAIN BODY LIST
Container(
width: screenWidth * 0.49,
child: Card(
color: Colors.white,
child: Column(
children: <Widget>[
Container(
//width: 200,
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
decoration: BoxDecoration(
color: Colors.black12,
),
child: Row(
children: <Widget>[
ClipOval(
child: Material(
color: Colors.white,
child: SizedBox(
width: 40,
height: 40,
child:
/*Image.asset(
'assets/icons/doc_icon.png'),*/
Icon(
Icons.playlist_add_check,
color: AppTheme.primaryColor,
),
),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_localization.localeString(name),
style: TextStyle(color: AppTheme.primaryColor),
),
],
),
),
),
],
),
),
Container(
child: Column(
children: _dynamicListWidget(list),
),
),
],
),
),
);
You need to set crossAxisAlignment as CrossAxisAlignment.start
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: mainBodyList,
);
I am trying to center Two elements in a Row widget that resides in a Colum widget. The last Row in this code is of interest. I have noticed that when I remove the "Flexible(...)" widget from that Row, then the Text centers horizontally. Otherwise, both elements stick to the left-hand side of the screen. I want both of the elements to stick to the center. I tried wrapping the Flexible widget into a Container and then Aligning that container to the middle, Flutter did not like that.
I am looking for the Two widgets in the last row to center horizontally
void main() => runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Example 1"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: Center(
child: ButtonBar(
children: <Widget>[
RaisedButton(
child: Text("Button"),
),
RaisedButton(
child: Text("Button"),
)
],
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
child: Center(
child: ButtonBar(
children: <Widget>[
RaisedButton(
child: Text("Button"),
),
RaisedButton(
child: Text("Button"),
)
],
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Email:"),
Flexible(
child: TextField(
textAlign: TextAlign.justify,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter Email",
),)),
],
),
],
),
floatingActionButton: FloatingActionButton(
child: Text("clock"),
),
),
));
A Row Widget will try to use as much space as possible (https://api.flutter.dev/flutter/widgets/Row-class.html)
if you wrap your children widgets inside a Flex and centre the Main Axis, you will see the children elements centred
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 1,
child: Text("Email:"),
),
Flexible(
flex: 1,
child: TextField(
textAlign: TextAlign.justify,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter Email",
),
),
),
],
),
In design, I have divided screen in three-part using Expanded but in Second part have a textfield when user try to input something the design overflows by some pixel, I have been trying to use SingleChildScrollView inside Expanded with container widget to get rid of the rendering problem but my design disappears.
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: _buildBackground(),
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
flex: 13,
//child:_toolBar('VENUE LOGIN')
child:MyWidget(headerText: 'Player Option',)
),
Expanded(
flex: 70,
child: Container(
margin: EdgeInsets.only(top: width*0.03),
decoration: BoxDecoration(color: Colors.transparent),child: PlayerOptionContainer(),),
),
Expanded(
flex: 17,
child: _bottomView1(width),
),
],
)
],
),
);
PlayerOptionWidget method
Widget PlayerOptionContainer(){
return Column(
children: <Widget>[
Expanded(flex:25,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(flex: 30,child: _logoContainer(width),),
Expanded(flex: 70,child: searchContainer(),),
],),),
Expanded(flex:75,child: Container(
decoration: BoxDecoration(color: Colors.transparent),
child: GridView.count(
crossAxisCount: 3,
children: List.generate(20, (index) {
return Container(
margin: EdgeInsets.only(left: width*0.02, bottom: width*0.02, right: width*0.02),
decoration: BoxDecoration(
color: MyColors.yellowBg,
borderRadius: new BorderRadius.circular(12.0),
),
child: Center(child: MyFeedTile(),),
);
}),
),
),)],
);
}
This is the design trying to achieve
But it gets overflow by some pixel
Common problem. There are a couple solutions
You can wrap body (Stack) in SingleChildScrollView
You can try resizeToAvoidBottomInset parameter of Scaffold:
Scaffold(
resizeToAvoidBottomInset: false, ... )
I have a ListView and I need an expanded vertical line on the left of it (See image below). I have achieved the following layout but it expands to infinite.
Here is the code for the above layout:
return Scaffold(
...
body: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 4.0),
color: Colors.grey,
width: 4.0,
child: SizedBox.expand(),
),
Flexible(
child: StreamBuilder( // Creates the list view
stream: ...,
builder: ...,
),
),
],
),
],
),
};
Line goes to infinite because of SizedBox.expand() but how to fit into the screen. Any suggestions?
Or is there a way to get this same effect from ListView item (Doesn't have a fixed size).
Don't use Column as Parent if you only has one child, this is working for me:
return Container(
child: Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 4.0),
color: Colors.grey,
width: 4.0,
),
Expanded(
child: ListView.builder(
// Creates the list view
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (context, index) {
return ListTile(
contentPadding: EdgeInsets.all(20.0),
title: Text(list[index].toString()),
);
},
),
),
],
),
);