Search code examples
flutterdartflutter-layout

Flutter Stack Widget: Bound a layer's size to the size of the underlying layer


So I have a Card with a column (dynamic size). I want to display an overlay (semi transparent + icon) over the whole card, without altering the card's size.

I have coded an example by using a Stack widget. Run on DartPad

The problem is, that the overlay should adapt to the size of the content in the layer below. But how does the Overlay know the size of that other layer?

double.infinity won't work, because the size of the card is not fixed and can't be fixed, because the content has a dynamic size.

Card(
      child: Stack(
        children: [
          // Content
          Padding(
            padding: EdgeInsets.all(10),
            child: Column(mainAxisSize: MainAxisSize.min, children: [
              // Content of dynamic size
              Text("q23123"),
              Text("q23123"),
              Text("q23123"),
              RaisedButton(
                child: Text("Display Overlay"),
                onPressed: (() {
                  if (_showOverlay == false) {
                    setState(() {
                      _showOverlay = true;
                    });
                  }
                }),
              ),
            ]),
          ),
          // Overlay
          _showOverlay == true
              ? Container(
                  height: double.infinity, // Overlay is too big -> should adabt to
                  width: double.infinity, // the size of the layer underneath
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                      begin: Alignment.centerLeft,
                      end: Alignment.centerRight,
                      colors: [Colors.transparent, Colors.red],
                    ),
                  ),
                )
              : Container( // Overlay deactivated
                  height: 0,
                  width: 0,
                ),
        ],
      ),
      color: Colors.blue,
    ))

Solution

  • You can copy paste run full code below
    In this case, you can use GlobalKey to get yourRenderBox.size
    code snippet

    class _MyHomePageState extends State<MyHomePage> {
      bool _showOverlay = false;
      GlobalKey _key = GlobalKey();
    
      Size _getSizes() {
        final RenderBox yourRenderBox = _key.currentContext.findRenderObject();
        return yourRenderBox.size;
      }
    
      @override
      Widget build(BuildContext context) {
       ...
              Padding(
                key: _key,
              ...
              // Overlay
              _showOverlay == true
                  ? Container(
                      height: _getSizes().height,
                      width: _getSizes().width,
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Problem'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      bool _showOverlay = false;
      GlobalKey _key = GlobalKey();
    
      Size _getSizes() {
        final RenderBox yourRenderBox = _key.currentContext.findRenderObject();
        return yourRenderBox.size;
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Center(
                child: Card(
          child: Stack(
            children: [
              // Content
              Padding(
                key: _key,
                padding: EdgeInsets.all(10),
                child: Column(mainAxisSize: MainAxisSize.min, children: [
                  // Content of dynamic size
                  Text("q23123"),
                  Text("q23123"),
                  Text("q23123"),
                  RaisedButton(
                    child: Text("Display Overlay"),
                    onPressed: (() {
                      if (_showOverlay == false) {
                        setState(() {
                          _showOverlay = true;
                        });
                      }
                    }),
                  ),
                ]),
              ),
              // Overlay
              _showOverlay == true
                  ? Container(
                      height: _getSizes().height,
                      width: _getSizes().width,
                      decoration: BoxDecoration(
                        gradient: LinearGradient(
                          begin: Alignment.centerLeft,
                          end: Alignment.centerRight,
                          colors: [Colors.transparent, Colors.red],
                        ),
                      ),
                    )
                  : Container(
                      // Overlay deactivated
                      height: 0,
                      width: 0,
                    ),
            ],
          ),
          color: Colors.blue,
        )));
      }
    }