4

For some reason, the Stack widget does not show the Container with the CustomPaint.

However if removed from Stack, it works fine. What am I missing here?

class _DemoNavBar extends State<DemoNavBar> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
        home:
        Stack(
          children: <Widget>[
            Container(child: CustomPaint(painter: CurvePainter()))
      ],
    )
    );
  }
}

class CurvePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint();
    paint.color = Colors.green[800];
    paint.style = PaintingStyle.fill;

    var path = Path();

    path.moveTo(0, size.height - 100); 

    path.lineTo(size.width * 0.5, size.height - 100); 
    path.quadraticBezierTo(size.width * 0.7, size.height, size.width * 0.9,
        size.height - 100); 
    path.lineTo(size.width, size.height - 100); 
    path.lineTo(size.width, size.height); 
    path.lineTo(0, size.height);
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }

Thanks!

user2511882
  • 9,022
  • 10
  • 51
  • 59

1 Answers1

10

Checking the source of CustomPaint it says

  /// The size that this [CustomPaint] should aim for, given the layout
  /// constraints, if there is no child.
  ///
  /// Defaults to [Size.zero].
  ///
  /// If there's a child, this is ignored, and the size of the child is used
  /// instead.

So, give it a size. Other solutions include 1) providing width and height to the parent Container of CustomPaint and 2) provide a child for the CustomPaint which will ignore the size provided in the solution below.


I checked this code to work fine. size: MediaQuery.of(context).size uses the complete screen size.

void main() {
  runApp(SO());
}

class SO extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DemoNavBar(),
    );
  }
}

class DemoNavBar extends StatefulWidget {
  @override
  _DemoNavBar createState() => _DemoNavBar();
}

class _DemoNavBar extends State<DemoNavBar> {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        CustomPaint(
          size: MediaQuery.of(context).size,
          painter: CurvePainter(),
        )
      ],
    );
  }
}

class CurvePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint();
    paint.color = Colors.green[800];
    paint.style = PaintingStyle.fill;

    var path = Path();

    path.moveTo(0, size.height - 100);

    path.lineTo(size.width * 0.5, size.height - 100);
    path.quadraticBezierTo(size.width * 0.7, size.height, size.width * 0.9, size.height - 100);
    path.lineTo(size.width, size.height - 100);
    path.lineTo(size.width, size.height);
    path.lineTo(0, size.height);
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

Now, the reason is since Container has no parent or child to provide the size it takes complete screen size and works fine without Stack. When a stack is used size goes to zero which is given to the custom painter.

Equivalent code can be written as

Stack(
  children: <Widget>[
    Container(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: CustomPaint(
        painter: CurvePainter(),
      ),
    )
  ],
);

the end result is

screenshot

Doc
  • 10,831
  • 3
  • 39
  • 63
  • How does it work without a size when removing it from the Stack then? – user2511882 Feb 02 '20 at 03:00
  • if you give width and height to the container inside the stack then those width and height will be used by custompaint. – Doc Feb 02 '20 at 03:03
  • what is the issue? – Doc Feb 02 '20 at 03:05
  • ```No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of(). This can happen because you do not have a WidgetsApp or MaterialApp widget``` – user2511882 Feb 02 '20 at 03:09
  • Yes, I know the reason; it is already fixed in the code. There needs to be a MaterialApp higher in the tree. I suggest you paste the code exactly as answered the check the result if it works for you. Comment the rest of your code and use the code in answer. – Doc Feb 02 '20 at 03:12
  • I wish this was mentioned in the class documentation in the website. – Wilson Silva Feb 02 '20 at 19:12
  • @WilsonSilva It is mentioned in the docs. Check https://api.flutter.dev/flutter/widgets/CustomPaint/size.html and https://api.flutter.dev/flutter/widgets/Container-class.html. But better explained in the source code. – Doc Feb 02 '20 at 19:58
  • @Doc Thanks. Good catch. I was expecting it to be documented in https://api.flutter.dev/flutter/rendering/CustomPainter-class.html. – Wilson Silva Feb 02 '20 at 20:48