今是昨非

今是昨非

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

Flutter Layout Basics - Stack Overlay Layout

Flutter Layout Basics - Stack Layout#

Stack 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 gradient shadows 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 position by setting the top, bottom, left, and right properties relative to the Stack, with at least one of them being non-null.

The size of the Stack Widget depends on all non-positioned child views. The position of non-positioned child views is 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, we need to write a child view that exceeds the Stack 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 seen.

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 the differences, here we use Row 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 passthrough, it uses the Row's Expanded layout; when StackFit is loose, it uses the layout of the child view; when StackFit is expand, it uses the layout of the 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.