1

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),),
    )
  ],
);
GoldenJoe
  • 7,874
  • 7
  • 53
  • 92
  • May I ask why you're trying to do this? As you've noticed flutter doesn't allow negative heights or insets as the rendering engine is optimized around not having to deal with edge cases like that. If you're only doing this for a couple of items, I'd suggest a CustomMultiChildLayout and laying out each of the children exactly where you want them, while if you're dealing with a large amount of objects I'd look into either using OverlapBox or writing a custom Sliver implementation to put in a CustomScrollView. – rmtmckenzie Dec 05 '18 at 22:58
  • It's not an edge case, it's very common when working with Text. Sometimes you must compensate for the blank space in a font's ascender or descender. Flutter has a Baseline widget which covers that use case, but lacks ways to compensate for the other attributes of a font. As such, manual offsets are necessitated. – GoldenJoe Dec 06 '18 at 00:10
  • Fair enough I suppose - Flutter's text handing isn't as powerful as it could be as it doesn't expose everything skia can do. But that's a pretty specific use-case and I'd guess that by playing around with RichText's textScaleFactor, and TextStyle's height, textBaseline, and fontSize you could figure something out. If you're having problems getting something in particular to render how you want I'd advise asking about that, otherwise see [this answer](https://stackoverflow.com/questions/48086486/does-flutter-support-negative-margin#answer-48103412) from one of flutter's main developers. – rmtmckenzie Dec 06 '18 at 00:33
  • Possible duplicate of [Does Flutter support negative margin?](https://stackoverflow.com/questions/48086486/does-flutter-support-negative-margin) – rmtmckenzie Dec 06 '18 at 00:35
  • Let's be careful about marking duplicate questions from a year ago when the API had barely been made public. – GoldenJoe Dec 06 '18 at 02:08

2 Answers2

2

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")),
    ],
)

enter image description here

Have a nice day...

Sapto Sutardi
  • 326
  • 4
  • 11
0

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.

MαπμQμαπkγVπ.0
  • 5,887
  • 1
  • 27
  • 65