I'm so confused about how the clipping system in Flutter works.
So I will start with this example, Non of the shadow has been clipped.
Even the shadow was overflow from its self or its parent container.
Container(
child: Column(
children: [
Text("test"),
Container(
margin: paddingTheme.edgeInsets,
child: Row(
children: [
ShadowBox(),
ShadowBox(),
ShadowBox(),
],
),
),
],
),
)
Now if I add more ShadowBox() until it overflows, All the shadow will be clipped.
For example:
Container(
child: Column(
children: [
Text("test"),
Container(
margin: paddingTheme.edgeInsets,
child: Row(
children: [
ShadowBox(),
ShadowBox(),
ShadowBox(),
ShadowBox(), // ADD THIS
],
),
),
],
),
)
Now even I change Row to be SingleChildScrollView or List it's still clipped, But not overflow
Container(
child: Column(
children: [
Text("test"),
Container(
margin: paddingTheme.edgeInsets,
child: ListView.builder( // CHANGE FROM ROW TO LIST
scrollDirection: Axis.horizontal,
itemCount: 5,
itemBuilder: (c, i) => ShadowBox(),
),
),
],
),
)
So the question is how it's work, And how can I prevent these shadows to be clipped?
Or it's a design flaw of Flutter itself?
I had fire this in the Flutter's issue.
https://github.com/flutter/flutter/issues/67858
As I understand from now, The default ClipBehaviour of Container Row Column is different from ListView and internal Overflow.
So we have a workaround by adding clipBehaviour: Clip.none to the ListView.
Edit: To get the overlap shadows and no clipping, you can try:
In ShadowBox() widget,
Container(
height: 100,
width: 100,
margin: EdgeInsets.only(top: 20,bottom: 20), <-----
decoration:BoxDecoration(
color: Colors.white,
boxShadow: [BoxShadow(color: Colors.blue,blurRadius: 12)]
),
),
As for why it is clipped?
In Flutter engine, clipping the shadow is default behavior.
If you go deep in code you will find that shadow's width/height is not taken into account while rendering children in ListView or any widget. So you have to take care of it.
Why is it not clipping in Row/Column then?
In Rows and columns, no clipping is visible because it assumes the height of Row/Column as per the parent's max height/width. So it's height/width is at Max/Infinity.
So if you increase the width and height of the ListView()'s parent Container() widget, clipping will not happen as well.
Related
I want to develop a UI just like Postman Desktop App. But When I add a text field and fix the sized button in a row it gives an error RenderFlex children have non-zero flex but incoming width constraints are unbounded. But I don’t want to give a fixed size to the text field through MediaQuery. As you can see in this video (Demo UI) Postman text field size is fixed when the screen size decrease it shows a horizontal scrollbar. I want the same behavior. Here is the code.
body: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
width: 300,
decoration:
BoxDecoration(border: Border.all(color: Colors.yellow)),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.red)),
child: Image.network(
ImageURL,
fit: BoxFit.fitWidth,
),
),
],
),
),
),
SizedBox(
child: Column(
children: [
Row(
children: <Widget>[
const Expanded(child: TextField()),
DarkButton("Save", () {}),
],
),
],
),
),
],
),
),
),
);
Add isDens = true in Textfield.
Just like this:
Expanded(child: TextField(decoration: InputDecoration(isDense: true),)),
this is because you use Expanded inside the SingleChildScrollView.
You can not use Expanded inside the SingleChildScrollView because it covers the maximum width or height.
Just remove SingleChildScrollView error was gone.
you may use listview for this or use CustomScrollView for that
I need to add padding (i.e. a space from screen edgess) for the first two widgets in a body column.
Scaffold(
body: Column(
children: [
// need to add padding for the next two widgets
Container(
child: Expanded(
child: Column(...),
),
),
Row(...),
// until here
Container(
child: Expanded(
child: Column(...
),
),
),
],
),
);
I tried to wrap them in a column again, but that gives the error:
RenderFlex children have non-zero flex but incoming height constraints
are unbounded.
I guess the problem is in wrapping the expanded column with new column. How to make that?
You need to wrap that newly created Column with another Expanded widget.
Scaffold(
child: Column(
children: [
Expanded(
child: Container(
child: Column(
children: [
Container(
child: Expanded(
child: Column(...),
),
),
Row(...),
],
),
),
),
...
margin inside Container does what you want
example
Container(
margin: EdgeInsets.only(
left: 10),
child:....
)
Bro, you need to wrap your first Column with Container first, or with SizedBox. The requirement is that you cannot set Column within unbounded Width or Height. Otherwise, it will give an error. So set it up first, and set the Expanded inside it.
I have a problem with building a specific layout in flutter.
What I need is:
Scrollable screen, with two columns, where the first col is of certian (but dynamic) height. And the second col has part of certain (but dynamic) height and the rest of the col I want to fill remaining space.
The code structure.
Row(
children: [
Expanded(
child: Column(children:[
someDynamicHeightWidgetsHere()])),
Expanded(child: Column(children: [
someWidgetsHere(),
here fill remainind space to match the first column]))
]
)
Use IntrinsicHeight, This widget only expands to its child height.
This class is useful, for example, when unlimited height is available and
you would like a child that would otherwise attempt to expand infinitely to
instead size itself to a more reasonable height.
Example:
IntrinsicHeight(
child: Row(
children: [
Expanded(
child: Column(
children: [
Container(
height: 800,
color: Colors.blue,
),
],
),
),
Expanded(
child: Column(
children: [
Container(
height: 400,
color: Colors.red,
),
Expanded(
child: Container(
color: Colors.yellow,
),
),
],
),
),
],
),
Output:
There are a lot of questions here already about Renderflex overflow, but I believe my use case might be a bit different.
Just the usual problem - having a Widget that is too big in a Row widget, and I get the A RenderFlex overflowed by X pixels ... error.
I want to create a Row that cuts off it's overflowing child Widget if they would be rendered outside it's area without getting an error.
First off, wrapping the last element in the Row widget with Expanded or Flexible does not work in my case, as recommended here and here and many other places. Please see code and image:
class PlayArea extends StatelessWidget {
#override
Widget build(BuildContext context) {
final dummyChild = Container(
color: Colors.black12,
width: 100,
child: Text('important text'),
);
final fadeContainer = Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Colors.black26,
Colors.black87,
],
),
),
width: 600,
);
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
color: Colors.redAccent,
child: Column(children: [
Expanded(
child: Row(
children: <Widget>[
dummyChild,
fadeContainer,
],
),
),
Expanded(
child: Row(
children: <Widget>[
dummyChild,
Expanded(
child: fadeContainer,
),
],
),
),
Expanded(
child: Row(
children: <Widget>[
Container(
color: Colors.black12,
width: 1100,
child: Text('important text'),
),
Expanded(
child: fadeContainer,
),
],
),
),
]),
),
);
}
}
Key points:
Using Expanded changes the width of Container, which changes the gradient's slope. I want to keep the gradient as it is
Even with Expanded widget, the Row is not prepared for the case when important text's area is too wide and does not fit the screen horizontally - it will get an overflow error for that Widget
it is technically working in the first case, because no red color is drawn on the right side on the green field, it 'just' has an error
How do I cut off the remaining space dynamically without any error - regardless of any screen size and content?
One solution I found is that
Row(
children: <Widget>[
dummyChild,
fadeContainer,
],
)
can be converted to
ListView(
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
children: <Widget>[
dummyChild,
fadeContainer,
],
)
Creating a horizontal list and preventing scroll on that.
edit.: just found out it that you'll get unbounded vertical height, so it's not the same.
I want to achieve the following look:
How can I make the FAB flex-ibly positioned in between these 2 widgets? (between top profile image and bottom profile info)
I've managed to make the 2 containers, but I haven't got a clue on how to position the FAB at the exact horizontal border of them.
My code (this is the entire widget tree, wrapped in a scaffold):
Row(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
flex: 4,
child: Container(
decoration: BoxDecoration(color: Colors.grey.shade300),
),
),
Expanded(
flex: 6,
child: Container(),
),
],
),
),
],
),
You can use a Stack & Positioned widget together to position the FAB as per your requirement.
Stack(
children:[
// Add your existing row & it's child here,
Positioned(
child: FloatingActionButton(
onPressed:(){ },
child: Icon(Icons.camera_alt)
),
right: 5,
top: MediaQuery.of(context).size.height * .3,
)
],
),
And the output:
Note: You may need to tweak the top value of the positioned widget to place the FAB accurately in your case. If you know the exact height of that image widget, you can set top as height - 28.