Sometimes I want to arrange items in a column with different amounts of space between each item. A typical implementation uses SizedBox or Container.padding, but neither permits negative values. Are there any ways to achieve negative spacing as of Flutter 1.0?
return Column(
children: <Widget>[
Container(height:20, width: 20, color: Color(0x800000FF),),
SizedBox(height: -10,), // Illegal, can't be negative
Container(height:20, width: 20, color: Color(0x80FF0000),),
Container(
padding: EdgeInsets.fromLTRB(0, -10, 0, 0), // Illegal, can't be negative
child: Container(height:20, width: 20, color: Color(0x8000FF00),),
)
],
);
The best way using transform. Less code :-).
If you want to increase position a Widget aka you want a "negative" margin, eg top (-10), you can do this:
Transform.translate set the Offset(x, y)
Column(
children: [
Text("Fist Text in Column"),
Transform.translate(
offset: const Offset(0, -10),
child: Text("Second Text in Column")),
],
)
Have a nice day...
There is actually an article about a negative margin in flutter. I believed that the SO answer mentioned in the comments was also discussed there.
In CSS, margins have various meanings in the various layout
models, most commonly, they are one of several values that contribute
to computing the offset that the block layout model uses to place
subsequent children; a negative total margin in this case merely means
the next child is placed above the bottom of the previous child
instead of after it.
In Flutter, as in CSS, there are several layout models; however,
there is currently no widget that is equivalent to the CSS block
layout model (which supports margin collapsing, negative margins,
skipping floats, etc).
Such a layout model could certainly be implemented, it just hasn’t
been implemented yet, at least not in the framework itself.
To implement such a layout model, you would create a RenderBox
descendant similar to RenderFlex or RenderListBody, probably providing
a way to set the margins of each child using a ParentDataWidget in the
same way that Flex children can have their flex configured using the
Expanded widget.
Probably the most complicated part of designing a new layout model
like this would be deciding how to handle overflow or underflow when
the children are too big or too small to fit the constraints passed to
this new layout render an object.
The RenderFlex render object has a way to distribute the space if the
children underflow, and considers it an error if they overflow (in
debug mode, this is shown by a yellow-and-black striped warning area
and a message logged to the console); the RenderListBody render the
object.
On the other hand, takes the view that the constraints must be
unbounded in the main axis, which means you can basically only use
this layout model inside a list (hence the name).
If writing a new layout model is not attractive, you could use one of
the existing layout widgets that allow overlapping children. A stack
is an obvious choice, where you set the explicit positions of each
child and they can overlap arbitrarily this is vaguely similar to the
CSS absolute position layout model. Another option is the CustomMultiChildLayout widget, which lets you layout and position each child in turn.
With this, you could position each child one after the other,
simulating negative margins by setting the position of the subsequent
child to a value that’s derived from the size and position of the
previous child, but such that the subsequent child’s top is above the
previous child’s bottom.
Flutter has a sophisticated but effective algorithm for rendering its
widgets. Margins and Paddings are analyzed at runtime, and the
final size and position of the widget are determined.
when you try to issue a negative margin you are purposefully creating
a not valid layout where a widget is somehow dropping out of the space
it is supposed to occupy.
Concluded that it is not ideal but there are some workarounds if really needed:
No, Flutter does not allow negative margins but just in case you still want your widgets to overlap each other…
you can use a Stack with Positioned which will allow you to generate
the layout which you can do with negative margins.
Related
I am using v-selects inside a flexbox, and I would like the v-selects's size to depend on the flexbox settings instead of changing depending on whether a long or short item is selected.
Is there a way to make the width independent of the selected item?
Yesterday I remembered that it didn't happen when I used a v-container, so I mimicked the css of a v-container but with a few changes to apply a different style.
Essentially, if the v-select has rather low width, you can't get around setting the width of the v-select manually if you want it to stay a certain size, which in the end is what v-col is effectively doing.
I wanted it to change depending on the parent's width so I used a percentage and subtracted the total flexbox gap (20px) divided by the number of items (2) in the parent, like this:
.v-select-class {
width: calc(50% - 10px);
}
Hope this helps someone in the future.
This is my tree:
Scaffold(-> Column(-> Expanded(-> ListView(-> Column(-> TextFields)))));
I want to limit the width of these TextFields (say, to 200px), but using SizedBox/Container/ConstrainedBox and setting a width/maxWidth on the Column isn't working; I have to wrap each individual TextField with a SizedBox for it to work- which adds a lot of fluff to my code.
Is there a better way to do this?
If you wrap your Column with a Container and set it to 200px, you'll not have to specify/wrap your TextFields individually anymore.
also looking at your hierarchy your Expanded widget will decide the max. width.
Scaffold(-> Column(-> Expanded(-> ListView(-> Container(width:200 -> Column(-> TextFields))))));
body: Container(
width: 200,
color: Colors.deepOrange,
child: Column(
children: [
TextField(),
],
),
),
I found the answer while watching https://www.youtube.com/watch?v=XcnP3_mO_Ms.
"If you put AspectRatio into something like Expanded, then that will
be forced by its parent to expand. Tightly fitted widgets like
Expanded don't give their children a choice-- harsh. If this happens
to you, just put something like Align between the Expanded and the
AspectRatio.
Align will be forced by Expanded to fill the area, but it will let its
child assume its own proportions. Thanks, Align!"
I have to wrap my Column in a Container, and then wrap the Container in an Align to break free of Expanded.
The issue is that TextField don't have a defined width so the Column doesn't know how to handle it and the Column needs to know the size of its child elements to properly render them. You best bet is wrapping your TextField in:
1. An Expanded widget (here the TextField will expand to fill the
available space)
2. A Flexible widget, or
3. Better still wrap it in a Container since you already know the width
you want (i.e. 200px).
Add Container at the top and give it width:200
Scaffold(-> Container(width:200 ->Column(-> Expanded(-> ListView(-> Column(-> TextFields)))));
Flutter newbie here.
Basically I'd like to reproduce the effect of the background in this video:
https://youtu.be/LcCtg1D_RIE?t=804
From what I have gathered so far, I can use a Stack widget to set some background layer, and use the repeat property of Image to get a repeating tile pattern. The following code does this reasonably well:
Widget build(BuildContext context) {
return Stack(children: <Widget>[
Container(
width: 5000,
height: 5000,
child: Image.network(
"https://www.scirra.com/images/articles/daf.png",
repeat: ImageRepeat.repeat,
)),
/* UI goes here */
]);
What I cannot figure out, is how to perform the animation. I have tried various scroll classes (like SingleChildScrollView) but they seem more designed for interactive use and do not allow bi-directional scrolling.
Another idea I have explored is providing a translation matrix to my Container, but while this indeed scrolls the pattern, it also leaves a black area at the edge of the screen.
I'm sure there exists a smart trick to easily achieve that effect - would someone have some clever input?
The CSS2.1 spec mandates that overflow other than visible establish a new "block formatting context". This strikes me as odd, that a property whose obvious purpose is to hide overflow without affecting layout, actually does affect layout in a major way.
It seems like overflow values other than visible combine two completely unrelated features: whether a BFC is created and whether the overflow is hidden. It’s not like "overflow:hidden" is completely meaningless without a BFC, because floats historically can overflow their parent element, hiding the overflow without changing the layout seems sensible.
What are the reasons behind this decision, assuming they are known? Have the people who worked on the spec described why this was decided to be the case?
I asked about this on the mailing list on your behalf; the thread can be found here. In summary, this has to do with scrolling content for the most part:
Fundamentally, because if the spec didn't say this, then having floats intersect with something that's scrollable would require the browser to rewrap (around intruding floats) the contents of the scrollable element every time it scrolls. This is technically what
CSS 2.0 required, but it was never implemented, and it would have been a huge problem for speed of scrolling.
-David
Most likely, it refers to scrollable content in a box that may occur outside of the float's parent but would intersect with the float. I don't think this is related to rewrapping content around a float within a scrollable container, as that already happens naturally, plus the float would clip into the container and scroll along with the rest of its content anyway.
Finally this makes sense to me. In fact, I'm going to provide an example here so hopefully it makes sense to you and anyone else who may be wondering. Consider a scenario involving two boxes with the same fixed height and overflow: visible (the default), of which the first contains a float that stretches beyond its parent's height:
<div>
<p>...</p>
</div>
<div>
<p>...</p>
<p>...</p>
</div>
/* Presentational properties omitted */
div {
height: 80px;
}
div:first-child:before {
float: left;
height: 100px;
margin: 10px;
content: 'Float';
}
Notice the similarity to one of the examples given in section 9.5. The second box here is simply shown to have overflowing content for the purposes of this answer.
This is fine since the content will never be scrolled, but when overflow is set to something other than visible, that causes the content to not only be clipped by the bounds of the box, but also to become scrollable. If the second box has overflow: auto, this is what it would look like had a browser implemented the original CSS2 spec:
Because of the float, attempting to scroll the content would cause the browser to have to rewrap it so it doesn't become obscured by the float (and what should happen to the part that scrolls out of the top edge?). It would probably look something like this when scrolled to the bottom:
The catch here is that the browser has to rewrap the content every time it repaints it during scrolling. For browsers that are capable of pixel-based smooth scrolling — which is to say, all of them — I can see why it would be a performance disaster! (And a user experience one, too.)
But that's for when the user can scroll the content, right? This would make sense for overflow: auto and overflow: scroll, but what about overflow: hidden?
Well, a common misconception is that a container with overflow: hidden simply hides content by clipping and cannot be scrolled. This is not completely true:
While scrolling UI is not provided, the content is still scrollable programmatically, and a number of pages perform just such scrolling (e.g. by setting scrollTop on the relevant element).
-Boris
Indeed, this is what it'd look like if the second box was set to overflow: hidden and then scrolled to the bottom with the following JavaScript:
var div = document.getElementsByTagName('div')[1];
div.scrollTop = div.scrollHeight;
Again, notice that the content would have to be rewrapped to avoid being obscured by the float.
Even though this wouldn't be as painful for performance as had scrolling UI been available, my best guess is that they made boxes with any overflow value other than visible generate a new BFC mainly for the sake of consistency.
And so, this change was brought about in CSS2.1, documented here. Now if you apply an overflow value other than visible only to the second box, what a browser does is push the entire box aside to make way for the float, because the box now creates a new block formatting context that encloses its contents, instead of flowing around the float. This particular behavior is specified in the following paragraph:
The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.
Here's what it looks like with overflow: auto for example:
Note that there is no clearance; if the second box had clear: left or clear: both it would be pushed down, not to the side, regardless of whether it established its own BFC.
If you apply overflow: auto to the first box instead, the float is clipped into its containing box with the rest of the content due to its fixed height, which is set to 80px in the example code given above:
If you revert the first box to height: auto (the default value), either by overriding or removing the height: 80px declaration from above, it then stretches to the height of the float:
This happens to be new in CSS2.1 as well, in that an element with height: auto that generates a new block formatting context (i.e. a block formatting context root) will stretch vertically to the height of its floats, and not just enough to contain its in-flow content unlike a regular box. The changes are documented here and here. The change leading to the side-effect of shrinking the box so that it does not intersect the float is documented here.
In both of these cases, no matter what you do to the second box, it will never be affected by the float because it has been restricted by the bounds of its container.
I know this will be a speculative answer, however after reading the specifications a few times here is my view on this:
What section 9.4.1 is talking about is any block element that does not fully contain or does not fill the containment space. For example when you float an element it is no longer filling 100% of the parent, like in-flow elements do. Inline blocks, table cells, and table captions are also elements that you can affect height and width but that are not intrinsically 100% of the parent (yes table>tr>td is one that would fill 100% of it's parent but it is designed to allow for multiple td's so the td doesn't count as it will automatically shrink to accommodate additional td's) this also applies to any overflow other than visible because it breaks the containment of the block element.
So if I am reading this correctly the way it works is the 9.4.1 section is referring to block elements that break the default containment rules of the block elements as specified by section 9.2.1
I'm building a strategy game in the browser since 2 years back. Its already actively played by a small crowed of people so it is a working game.
Our problem is that its resource hungry. Basically you want opera or chrome. IE9 is more or less unplayable and firefox can be quite slow on some maps.
The game is a tile based top down game using 64x64pixel DIVs for the map.
We are currently in the end phase and we are focusing on optimizations. One of the things that eat resources is our animated water. We have 32 different tiles of water split into 15 frames each. So 480 64x64 images in one .gif file that is 1.1 mb.
Here is a link to the water: http://www.warbarons.com/beta5/terrain/water/water2.gif
Our game uses Fog of War to hide enemy units and castles that you cant see just like any RTS game. So on top of the .gif there is usually a layer with a transparent PNG.
It seems like this solution is quite demanding on the browser. When I scroll the map to show water in FireFox CPU goes up to 25% while its around 4-5% when no water is in sight.
I've been googling for a few days now trying to get an idea of a better technique. I've found two other way of doing this, either with a canvas tag which is iterating over a spreadsheet or using CSS to loop over a spreadsheet.
The problem I see with those two options is that all water tiles must remain in sync. If one starts playing before another one the waves wont be in sync which will break the seamless look.
I wonder if anyone have an idea to solve this? I know that having multiple gif animations will result in the out of sync problem.
Is there some cleaver way to use canvas to do this? Is it even possible to mix canvas with divs or would that require that we change the whole map engine?
Any help would be greatly appreciated.
Bit of a novice work around and a longshot, but:
For preparation, make a sprite-sheet of all of the different types of water tiles, with the first frame on the left, with a new row for each type, descending down.
Create a <div> with an 'overflow' attribute of 'hidden' behind the canvas
Make the background of the canvas transparent
Inside of the div, you can use <div>s for the water tiles and adjust their 'margin' attributes to match the position of the map
Give them all a class designation 'water', as well as a class to match the type of water tile (like 'dockleft', 'beachtop', etc.)
In your <style> element, make a class rule '.water'
Give the rule the 'background-image' attribute, linking to whatever and wherever your sprite-sheet is
For each type of water tile, create a class rule that corresponds to each tile-type and give them a matching y position for the sprite-sheet
Create a new <style> element with an id, one that will contain the background-position of all of the frames
Create a javascript variable to conatin the x position of all of the backgrounds
Inside your game loop, decrement the variable by 64 for whenever you want the sprite to change (until it equals 960, then set it 0)
When the variable changes, set the contents of the new <style> element to the new CSS rule for its 'background-position-x' using the variable
Meh. A little much, I know, but better than looping through an array and gobbling up system resources, changing each element individually (at least I assume so). Here's a simplified code sample:
<script type="text/javascript">
var pos = 0; // background-position-x variable
function loop() {
document.getElementById('changeMe').innerHTML = ".water{background-position-x:" + pos + "px;}"; //changes the contents of the <style> with the id 'changeMe'
//changes the <style> with id 'Change'
pos -= (pos == 960) ? -960 : 64; //assuming your sprite-sheet is oriented horizontally
setTimeout('loop();', 100);
}
</script>
<style type="text/css">
/* Remains unchanged */
.water {
width: 64px;
height: 64px;
background-image: url('spriteSheet.png');
}
.dockleft{
background-position-y: 420px;
/* If all of your sprites are on one sheet, you can set the
'background-position-y' attribute for each type of water tile and
give the 'water' class one sprite-sheet url for all of the types */
}
</style>
<style id="changeMe" type="text/css">
/* Changed by 'loop()' */
</style>
<body onload="loop();">
<div class="water dockleft"></div>
</body>