I have simple ListView with Custom Widgets in it:
#override
Widget build(BuildContext context) {
return Container(
height: Constants.width(context) / 2.5,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
wishlist.name,
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
Container(
height: 200,
color: Colors.transparent,
child: new Container(
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(40.0),
bottomLeft: const Radius.circular(40.0),
)),
),
),
],
),
);
}
The problem is that right now I am setting the Containers height to 200. But I would like the Container to simply fill all the space that is left. What is the way to make the height dynamically? (from the bottom of my Text to the bottom of the whole Container)
Wrap your Container by Expanded
PS : Probably you have to add mainAxisSize:MainAxisSize.min to your Column
Related
How do I create a voting progress bar in Flutter that starts from both end, where green extends from left side in green color if people voted YES and red extends from right side in green color if people voted NO . I have tried to find in Pub dev and can't find something like this. Would like to know how to create one as most of the tutorial I found, the progress bar only extends from one side instead of both sides. Something like this to clarify what I want to do
Maybe like this :
Widget _voteWidget(int yesVote, int noVote) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 20,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30)),
),
child: Row(
children: [
Flexible(
flex: yesVote,
child: Container(
decoration: const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(topLeft: Radius.circular(30), bottomLeft: Radius.circular(30)),
),
),
),
Flexible(
flex: noVote,
child: Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.only(topRight: Radius.circular(30), bottomRight: Radius.circular(30)),
),
),
),
],
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('${yesVote.toString()} Yes'),
Text('${noVote.toString()} Yes'),
],
)
],
),
);
}
use linearprogress indicator , if you want to add any decoration, just wrap with your custom widget
class MyWidget extends StatelessWidget {
int yes = 8736;
int no = 520;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20),
child: LinearProgressIndicator(
minHeight: 20,
color: Colors.green,
backgroundColor: Colors.red,
value: (yes / (yes + no)),
));
}
}
result:
I have a column inside a listview. The column has image at the top and text in the bottom. I would like the text to stay within the width of the image and wrap. Right now the text does not wrap. Here is how the image and text in the column look like. Any body know how to do that?
Thanks in advance.
Here is the code of the column:
Row(
children: [
Container(
alignment: Alignment.centerRight,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(12),
border: Border.all(width: 1, color: AppColors.pink2),
),
child: Column(
children: [
ConstrainedBox(
constraints:
BoxConstraints(maxHeight: 300, maxWidth: width - 50),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image(
image: MemoryImage(chatMessageModel.rawData!),
fit: BoxFit.cover,
),
),
),
Padding(
padding: const EdgeInsets.all(14),
child: Text('I need this text to wrap around'),
),
],
),
),
],
)
You can use Flexible with AutoSizeText Widget to make it possible.
AutoSizeText Widget align your text size by corresponding your screen size
Flexible Widget adjust your text position
Working code :
Flexible(
child: AutoSizeText(
'I need this text to wrap around',
style: const TextStyle(
fontWeight: FontWeight.w400,
color: Color.fromRGBO(0, 0, 0,
1), //rankingNoColors(index)
fontSize: 24.0,
fontStyle: FontStyle.normal,
),
),
);
I figured I can draw ripple over an image by enclosing the image in Ink(decoration: BoxDecoration(image: ...)), but how can I do the same for Text?
This is supposed to be a card with an image on top and a title and some other information at the bottom:
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final post = _postModel.post;
return Material(
color: theme.colorScheme.background,
child: InkWell(
onTap: () {},
splashColor: Colors.red,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (post.imageUri != null)
// This image IS covered by the ripple (what I need)
AspectRatio(
aspectRatio: 5 / 3,
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
image: DecorationImage(
image: NetworkImage('https://picsum.photos/700'),
fit: BoxFit.cover,
),
),
),
),
// This must be underneath the ripple, but isn't.
Text(post.title, style: theme.textTheme.headline5),
Container(
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 5),
color: Colors.transparent,
height: 60,
child: Row(
children: <Widget>[
// This is also covered by the ripple
Ink(
height: 35,
width: 35,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage('https://picsum.photos/100'),
),
),
),
SizedBox(width: 5),
// This must be underneath the ripple but isn't
Ink(
// decoration: Decoration,
child: Text(
post.author,
style: theme.textTheme.caption,
),
),
Spacer(),
],
),
),
],
),
),
),
);
}
When I press, the ripple covers both images as expected, however, I can't figure out how to make the ripple cover the text widgets as well. I tried wrapping the text in an Ink widget (the last one), but it doesn't work - the text is still displayed over the ripple.
Unpressed:
Pressed (the text is visible):
I having an issue with a Flutter Widget tree I am building:
I Want the Buttons on the Bottom to be bigger and fill all the available space from the text above to the bottom of the screen.
Here my current Code:
class Body extends StatelessWidget {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: Column(
children: [
UpperDetailsContainer(),
TitleAndPrice(),
//The Row below contains the Two Buttons
Expanded(
child: Row(
children: [
Container(
width: size.width / 2,
child: TextButton(
child: Text("Buy Now"),
style: TextButton.styleFrom(
backgroundColor: kPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(50)
)
)
),
),
),
Container(
width: size.width / 2,
child: TextButton(
child: Text("Description"),
style: TextButton.styleFrom(
backgroundColor: kPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50)
)
)
),
),
),
],
),
)
],
),
);
}
}
I have already tried:
Making the upper widgets smaller
Adding Mainaxisaligment.spacebetween to the surrounding column
Adding Crossaxisaligment.stretch to the Row that contains the buttons
Removing SafeArea bottom / SafeArea as a whole
Setting the height for the buttons manually as an absolute value, but I don't really wanna do this for obvious reasons
What else can i do? And where does that grey bottom Stripe come from?
add crossAxisAlignment: CrossAxisAlignment.stretch to the row, so that it fills all available vertical space
note: you need the Expanded widget so that the constraint your row gets, isn't infinite
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
height: size.height * 0.7,
child: Container(
color: Colors.amber,
),
),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildBuyNowButton(size),
_buildDescriptionButton(size),
],
),
)
],
),
);
}
Runnable example: https://www.dartpad.dev/4f568d8e0a334d23e7211207081356b4?null_safety=true
I want the Container attached to the body of the Scaffold to occupy the space of it's child, which is the Padding widget in this case.
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
);
Below is the screenshot for the above code:
But I also want the padding widget to be pushed to the bottom of the screen. To achieve this I wrapped the Padding widget with the Expanded widget, and later wrapped the Expanded widget with a Column widget, as shown below:
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
],
),
),
);
Now that the contents of the Padding widget have got pushed to the bottom of the screen, but the Expanded widget, tries to occupy all the available space. I don't want this to happen.
I don't want the height of the Padding widget to increase. Below is the screenshot after updating the code:
Another issue that's concerning me is, where should I be adding the SingleChildScrollView, as I would experience the "Bottom overflowed by -- px" error when the user would tap on the TextFormFields to input the email and password.
I did raise this issue earlier as well but wasn't much luck, so thought would organize the code and explain it in detail so that it would be easy for others to understand and help.
Thank you so much for your help in advance.
AFTER APPLYING SOLUTION SUGGESTED BY #SoundConception
try adding this to your Column widget :
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
In your first code example you have:
...
body: Container(
...
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
The mainAxisSize: MainAxisSize.min specifies that the Column should be as small as possible in height, effectively shrink wrapping it to the height of its children.
The Padding just adds the specified dp of padding around Column widget.
This means the child of the Container has a fixed height equal to the sum of the Column children heights plus (kSpacingUnit * 3.0) dp of padding top and bottom.
Since the Container child height is fixed, the Container will size itself to the height of it's child.
In your second code example you have:
body: Container(
...
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
],
),
),
Here the outermost Column has a single child that is an Expanded which means this will take up all the available room in the Column.
The innermost Column has mainAxisAlignment: MainAxisAlignment.end meaning its children will align to the bottom of the Column. The height of your Padding has not expanded.
You ask about using a SingleChildScrollView. I assume you want the white background decoration to remain stationary, and only the contents of the Column should be able to scroll.
Try something like the following:
return Scaffold(
...
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
),
);
Note: You'll need to make sure your EmailSignInForm() and SocialMediaLoginWidget() do not have unbound height.
My guess is your EmailSignInForm() probably utilises a Column. If so set it's mainAxisSize to min.