Why is this icon being clipped? - flutter

As you can see, the face icon on the right is being clipped and I'm not sure why.
Here is my code:
new Container(
padding: new EdgeInsets.fromLTRB(style.wideMargin, style.wideMargin * 2,
style.wideMargin, style.wideMargin),
decoration: new BoxDecoration(backgroundColor: Colors.white),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new PrecisionTextOverflow(
'Name of a thing',
lineWidth: style.longLineWrappingWidth,
mainTextStyle: style.blackParagraphText),
// Because PrecisionTextOverflow paints itself directly, the UI
// doesn't know its size so we use a blank Text object to make the
// column center itself correctly.
new Text(' '),
],
),
),
new Transform(
transform:
new Matrix4.translationValues(0.0, -style.defaultMargin, 0.0),
child: new IconButton(
padding: EdgeInsets.zero,
icon: new Icon(Icons.face,
size: style.headingText.fontSize,
color: style.favoriteColor[isItemFavorite]),
onPressed: favoritePressed,
),
),
],
),
)
That PrecisionTextOverflow is a class I made of a StatelessWidget that uses a CustomPainter to paint text on the screen. I don't imagine it's related to the issue at hand, but just FYI.
I've tried removing the padding from the outer container but it doesn't help. I've tried adjusting the transformation to shift the icon to the left but it just shifts it in its clipped form. What am I doing wrong? How can I correct this?
Edit:
Okay, I did a render tree dump and it looks like the enclosing Row sets its height as 24.0, which passes on down to the IconButton which gives itself a size of (24.0, 24.0). Is there a way to increase the height of a Row? Or should I rethink my whole structure?

You're setting the size on the Icon, rather than the IconButton. If you move the size argument to IconButton it should work.
What's going on is that the IconButton is defaulting to 24.0, and since you have it in an unbounded space it's being size-limited to 24.0 via a LimitedBox. It then tries to pass that size down to the Icon via an IconTheme inherited widget, but the Icon has been told to ignore that and be size 30.0 regardless.
I'll improve the docs.

I had the same problem for a different reason
Wrapping the IconButton in a Container with a fixed height and width can cause it to clip like in the example.

Related

Alignment taking into consideration Material design padding

I want to show a progress bar with a button on the right side as in the image below. The margin on the left and right should be visually equal. Instead, the spacing on the right is larger than on the left. This is because the IconButton I'm using adheres to material design and has a bunch of extra space around it.
My code places the progress bar in a Row. Above it I also have a label in a Row. I want the right-aligned label to be aligned to the button. What's the correct way to align taking into consideration any padding that material design might have added?
Here's what my code looks like:
return Container(
padding: 10,
child: Column(
children: [
Row(children: [Text("Left aligned text"), const Spacer(), Text("Right aligned text")]),
const SizedBox(height: 10),
Row(children: [
Expanded(
child: LinearProgressIndicator(backgroundColor: Colors.darkBlue, color: Colors.blue, value: 55, minHeight: 20)),
IconButton(
icon: Icon(Icons.stop_circle_outlined),
padding: const EdgeInsets.all(0),
)
])
],
));
I don't think there is a way to do this. I wound up just making my own version of IconButton without the padding.

Flutter Stack: how to place items at the bottom

I have the following widget StackedIcons
reuturn Container(
color: Colors.green,
child: Stack(
clipBehavior: Clip.none,
children: [
CircleAvatar(), Positioned(left: 15, child: PlusOne())
]),
);
which I want right aligned inside another widget
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [StackedIcons(match: match)]
)
and this is what I get
This looks good in terms of what I want to achieve (the plus one on top of the user avatar). However it overflows the parent container.
If I use right offset for positioned the order of the icons will be inverted and I don't want that.
If possible I would like to specify to Stack place the element below the current one (rather than on top).
The output I want is to have this widget rigth aligned without going over the padding of the parent. If I remove the Clip.none behaviour I get
A possible solution might be to place your PlusOne inside the green Container, and then give the Avatar some offset on the right instead.
return Container(
color: Colors.green,
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned(right: 15, child: CircleAvatar()),
PlusOne(),
]),
);
I'm not sure how this would affect things if you were to have multiple avatars and then the plus icon, but if you haven't tried this, it might work for you.

Flutter: how to center a child, but set a limit on how big it can grow on one side of the margin

I have a home/login screen which is made up of a column that fills the entire screen like so:
Column(
children: <Widget>[
Expanded(
child: Container(
child: Logo(),
),
),
showThis ? This() : That(),
],
),
The second child of the column is dynamic and can have different heights, and this screen will have inputs so the keyboard will also affect the height.
I want to center Logo() vertically within the container when it's small (e.g. when keyboard is active), but limit how much the 'top margin' is able to grow, so that when the keyboard is hidden and This()/That() is small enough, Logo() will be in a static position on the screen, say 150 from the top (no longer centred vertically).
One method I have tried was using 2 empty Expanded() above and below Logo() and wrapping the top part in a ConstraintedBox(), but I am not able to get it to behave correctly.
Have you tried with Center() and also if you wanna in a specific position use Stack, for example
Stack(
children: <Widget>[
showThis(),
Positioned(top: 150, child: Logo())
],
)
This is what ended up working for me:
Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
// constrain top spacing with a max height
Flexible(child: Container(height: 160)),
_logo(),
Spacer(),
],
),
),
_bottomWidget(),
],
),

Flutter material button with unwanted padding/additional width

I can't figure out what's giving this button extra width/padding. The image used is cropped so has no spacing to the left or right and you can see in the attached screenshot from the dev tools that it doesn't occupy the width. Somehow the button has extra width but I don't know where it's coming from.
I have another identical button next to it and with the added space it's causing overflow.
Changing the image size with the width parameter doesn't affect the amount of space the material button takes up either. It seems to be a fixed size.
This is the whole code:
Scaffold(
body: Row(
children: <Widget>[
MaterialButton(
child: Image.asset("images/male.png", width: 33)
)
],
),
);
I also tried other buttons like FlatButton and RaisedButton but they are the same with this additional width/padding. I also tried setting padding with on the button to EdgeInsets.all(0) but that doesn't change anything either.
The extra space is from the minWidth default value which is taken from the current ButtonTheme (you can see that from the MaterialButton source code). You can remove the extra space by adding minWidth to 0 and padding to 0 to your MaterialButton widget. Something like this:
Scaffold(
body: Row(
children: <Widget>[
MaterialButton(
padding: EdgeInsets.all(0),
minWidth: 0,
child: Image.asset("images/male.png", width: 33),
)
],
),
);
Use a container, where you can specify the width
Scaffold(
body: Row(
children: <Widget>[
new Container(
width: 33,
child : MaterialButton(
child: Image.asset("images/male.png")
),
],
),
);

Make container widget fill parent vertically

TL;DR Need the container to fill the vertical space so that it can act as a ontap listener. Have tried most solutions but nothing seems to work.
So what I am trying to do is to make my container fill up the vertical space while still having a fixed width. Two first is what I have and third is what I want. The idea is to have the container transparent with a gesture ontap listener. If anyone have a better idea as for a different solution, feel free to suggest.
Widget build(BuildContext context) {
return new GestureDetector(
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _handleDragEnd,
child: new Stack(
children: <Widget>[
new Positioned.fill(
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Container(
child: new IconButton(
padding: new EdgeInsets.only(top: 16.0, bottom: 16.0, left: 24.0, right: 24.0),
icon: new Icon(Icons.warning),
color: Colors.black12,
onPressed: () {},
)
),
],
),
),
new SlideTransition(
position: new Tween<Offset>(
begin: Offset(0.0, 0.0),
end: const Offset(-0.6, 0.0),
).animate(_animation),
child: new Card(
child: new Row(
children: <Widget>[
new Container(
width: 20.0,
height: 20.0,
color: Colors.amber,
),
new Expanded(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_getListTile(),
_ifStoplineIsToBeShown()
],
),
)
],
)
),
),
],
)
);
}
I am quite sure that i have been missing something considering the fact that I have tried a lot of different things and nothing seems to work.
I have also uploaded an image with the debug painting here.
PS. I know I have set the height to a fixed value, but this is the only way to show the container.
The trick is to combine an IntrinsicHeight widget and a Row with crossAxisAlignment: CrossAxisAlignment.stretch
This force the children of Row to expand vertically, but Row will take the least amount of vertical space possible.
Card(
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: 20.0,
color: Colors.amber,
),
// Expanded(...)
],
),
)
)
To stretch the container to full height of the parent use property constraints:BoxConstraints.expand() in container widget. Container occupy the complete space independent of the of child widget
Container(
color: Colors.green,
child: Text("Flutter"),
constraints: BoxConstraints.expand(),
)
Please refer the link Container Cheat sheet for more about container
Simply pass in: double.infinity.
If you want a Container to fill all available space, you can just pass in:
width: double.infinity,
height: double.infinity
Explanation:
In Flutter, a child widget cannot exceed the "layout constraints" imposed by its parent widget. During the layout phase, Flutter engine uses a constraint solver to automatically correct "out-of-bound" values into what's allowed by its parent constraints.
For example, if you have a Container that's 50x50, and for its child, you pass in another Container that's 300x300, the inner container will be automatically corrected to "not exceed its parent", thus 50x50. Therefore, using sufficiently large values would always make sure you "fill parent".
In fact, even BoxConstraints.expand() exploits the same idea internally. If you open up the source code of expand(), you will see:
/// Creates box constraints that expand to fill another box constraints.
///
/// If width or height is given, the constraints will require exactly the
/// given value in the given dimension.
const BoxConstraints.expand({
double width,
double height,
}) : minWidth = width ?? double.infinity,
maxWidth = width ?? double.infinity,
minHeight = height ?? double.infinity,
maxHeight = height ?? double.infinity;
So if you are absolutely certain you want to fill all spaces, you can intuitively pass in a number bigger than the parent (or larger than the whole screen), like double.infinity.
As of Jan 2020 the simplest is to use an Expanded Widget
Expanded(flex: 1,
child: Container(..),
),
https://api.flutter.dev/flutter/widgets/Expanded-class.html
There are many answers which suggest using two things
constraints: BoxConstraints.expand(),
height: double.infinity,
But both these answer will give you an error like
BoxConstraints forces an infinite height.
We can avoid these by calculating the height of the screen like
App Bar
Top Bar Space(Exist on the above App Bar)
Remaining screen
1. Get the MediaQuery
final mediaQuery = MediaQuery.of(context);
2. Declare the AppBar Widget and same App Bar instance should be used in Scaffold App Bar
final PreferredSizeWidget appBar = AppBar(
title: Text('Home'),
);
3. Use calculated height
Container(
width: mediaQuery.size.width,
height: (mediaQuery.size.height -
appBar.preferredSize.height -
mediaQuery.padding.top),
color: Colors.red,
),
Output:
Set the height or width of a container to double.maxFinite
Container(
height: double.maxFinite,
width: 100,)
You can make your widget take the full size of a Container widget, and then set the container's height and/or width to double.maxFinite. This will make the Container take the height and/or width or its parent widget
I propose using Expanded widget (which allows us to avoid IntrinsicHeight widget), combine it with the Container's alignment property and therefore make it work properly even if the Container is not the only one at the screen.
Expanded(
child: Container(
alignment: Alignment.center,
child: Text('Your text', textAlign: TextAlign.center))),
That way one also avoids potential app's crash which occurs often when you accidentally expand to infinity some parts of the widget tree both horizontally and vertically (that is why you are not able to use BoxConstraints widget in many cases).
One can read more about the problems of passing constraints in Flutter here - a must read: https://medium.com/flutter-community/flutter-the-advanced-layout-rule-even-beginners-must-know-edc9516d1a2
This work works for me
height: MediaQuery.of(context).size.height,