今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

Flutter Layout Basics - Stack Overlay Layout

Flutter Layout Basics - Stack Overlay Layout#

Overlay layout is suitable for situations where child views are stacked together, and their positions can be determined relative to the boundaries of the parent view.

For example, it can be used to add text over an image, or to add a gradient shadow over a button, etc.

The Stack Widget's child views can either be positioned or non-positioned. Positioned child views refer to those wrapped in a Positioned widget, which confirm their positions relative to the Stack by setting the top, bottom, left, and right properties, with at least one of them not being null.

The size of the Stack Widget depends on all non-positioned child views. The positions of non-positioned child views are determined by the alignment property (when alignment is left-to-right, child views start from the top left corner; when alignment is right-to-left, child views start from the top right corner).

Basic Usage of Stack#

Common Properties of Stack#

  • Common properties of Stack
    • children: Child views
    • alignment: Alignment of child views
      • topLeft: Top left aligned
      • topCenter: Top center aligned
      • topRight: Top right aligned
      • centerLeft: Center left aligned
      • center: Center aligned
      • centerRight: Center right aligned
      • bottomLeft: Bottom left aligned
      • bottomCenter: Bottom center aligned
      • bottomRight: Bottom right aligned
    • clipBehavior, clipping, which may affect performance
      • Clip.hardEdge: This option is the default for Stack
      • Clip.antiAlias: Smooth clipping
      • Clip.antiAliasWithSaveLayer
      • Clip.none: No clipping needed
    • fit: Child view filling method
      • StackFit.loose: Uses the size of child components
      • StackFit.expand: Fills the area of the parent view
      • StackFit.passthrough: Pass-through, uses the layout method of the Stack's parent view
    • textDirection
      • TextDirection.ltr
      • TextDirection.rtl

Common properties of Positioned are as follows:

  • Common properties of Positioned
    • child
    • height
    • width
    • bottom
    • left
    • right
    • top

Alignment#

The code is as follows:


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var stack = new Stack(
      alignment: Alignment.bottomRight,
      children: [
        new Container(
          width: 300.0,
          height: 300.0,
          color: Colors.orange,
        ),
        new Container(
          width: 200.0,
          height: 200.0,
          color: Colors.green,
        ),
        new Text(
          'alignment bottomRight',
          style: TextStyle(color: Colors.white, fontSize: 21),
        )
      ],
    );

    return MaterialApp(
      title: 'StackView Widget',
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('StackView Widget'),
        ),
        body: Center(
          child: stack,
        ),
      ),
    );
  }
}

The effect is as follows:

image image image

From the comparison above, it can be seen that the alignment property affects the arrangement of the Stack's child views.

clipBehavior Property#

To conveniently observe the effect of clipBehavior, a child view that exceeds the Stack needs to be written using the Positioned Widget, setting top and left to negative values.

The code is as follows:


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var stack = new Stack(
      clipBehavior: Clip.antiAliasWithSaveLayer,
      children: [
        new Container(
          width: 300.0,
          height: 300.0,
          color: Colors.orange,
        ),
        Positioned(
            child: new Container(
              width: 200.0,
              height: 200.0,
              color: Colors.green,
            ),
            left: -20,
            top: -20),
        new Text(
          'clip antiAliasWithSaveLayer',
          style: TextStyle(color: Colors.white, fontSize: 21),
        ),
      ],
    );

    return MaterialApp(
      title: 'StackView Widget',
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('StackView Widget'),
        ),
        body: Center(
          child: stack,
        ),
      ),
    );
  }
}

The effect is as follows:

image image image image

From the above, the effect of clipBehavior can be observed.

fit Property#

The filling method of fit, the expand and loose properties of fit are easy to distinguish, but the difference between loose and passthrough properties needs special attention. To easily distinguish them, here Row is used as the parent view of Stack.

Simply put, expand fills the parent view; loose follows the size of the child view; passthrough follows the constraints of the parent view's parent view.

The code is as follows:


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var stack = new Stack(
      // alignment: Alignment.bottomRight,
      fit: StackFit.passthrough,
      children: [
        new Container(
          width: 300.0,
          height: 300.0,
          color: Colors.orange,
        ),
        new Container(
          width: 200.0,
          height: 200.0,
          color: Colors.green,
        ),
        new Text(
          'StackFit passthrough',
          style: TextStyle(color: Colors.white, fontSize: 21),
        ),
      ],
    );

    return MaterialApp(
      title: 'StackView Widget',
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('StackView Widget'),
        ),
        body: Center(
          child: Row(
            children: [Expanded(child: stack)],
          ),
        ),
      ),
    );
  }
}

The effect is as follows:

image image image

From the above, it can be seen that when StackFit is set to passthrough, it uses the layout of Row's Expand; when StackFit is set to loose, it uses the layout of child views; when StackFit is set to expand, it uses the layout of Stack.

Using Stack to Achieve Gradient Background Effect#

The code is as follows:


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var stack = SizedBox(
      width: 250,
      height: 250,
      child: Stack(
        children: [
          Container(
            width: 250,
            height: 250,
            color: Colors.orange,
          ),
          Container(
              padding: const EdgeInsets.all(5.0),
              alignment: Alignment.center,
              decoration: BoxDecoration(
                  gradient: LinearGradient(
                colors: [
                  Colors.black.withAlpha(0),
                  Colors.black12,
                  Colors.black45,
                ],
                begin: Alignment.topCenter,
                end: Alignment.bottomCenter,
              )),
              child: const Text('Foreground Text',
                  style: TextStyle(color: Colors.white, fontSize: 20.0))),
        ],
      ),
    );

    return MaterialApp(
      title: 'StackView Widget',
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('StackView Widget'),
        ),
        body: Center(
          child: stack,
        ),
      ),
    );
  }
}

The effect is as follows:

image

References#

Stack Dev Doc
Positioned Dev Doc
StackFit Dev Doc
Flutter Free Video Season 3 - Layout

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.