Search code examples
flutterdartflutter-layout

How do I make a widget float on top of other widgets without affecting the underlying layout?


I wanted to make a widget float on top of another widget without affecting the underlying layout. What I mean by that is, let's see the TextField widget with the decoration's border property set to OutlinedInputBorder.

Column(
  children: <Widget>[
    Container(
      width: double.infinity,
      height: 56,
      color: Colors.amber,
    ),
    TextField(
      decoration: InputDecoration(
        filled: true,
        labelText: 'Email',
        border: OutlineInputBorder(
          borderSide: BorderSide.none,
        ),
      ),
    ),
  ],
);

enter image description here

As you can see, the floating label text is floating on top of the underlying widgets without affecting how the underlying widgets are laid out while the label is sticky to the text field widget. AFAIK, this cannot be accomplished with the Stack widget. The same goes for the IconButton ripple effect. The ripple effect expands bigger than the actual size of the IconButton widget without affecting how the button is laid out in the widget tree. How do make this type of widget structure?


Solution

  • You can use the Transform widget to manipulate the area and bring it back with Stack + Positioned.fill to position the area to bottom layer but keep the layout as the top widget.

    Like the example below using Transform.scale:

    Column(
      children: <Widget>[
        Container(
          width: double.infinity,
          height: 56,
          color: Colors.amber,
        ),
        Stack(
          children: [
            Positioned.fill( // <- create area same as the "hello" text
              child: Transform.scale( // <- scale 3x the area
                scale: 3,
                child: Container( // <- fill the area with red
                  color: Colors.red,
                ),
              ),
            ),
            Text('hello'),
          ],
        ),
      ],
    ),
    

    And the result:

    demo1

    From the example above, the layout still use the "hello" text and the red area expands bigger than the actual size of the "hello" text, just like what you said about IconButton ripple effect.

    Another example using Transform.translate:

    Column(
      children: <Widget>[
        Container(
          width: double.infinity,
          height: 56,
          color: Colors.amber,
        ),
        Transform.translate(
          offset: Offset(0, -10),
          child: Text('hello'),
        ),
      ],
    ),
    

    enter image description here

    The result is like TextField labelText, same as what you gave the example above.

    Hopefully it can solve your problem, Thanks 😉