Why is CustomPaint affected by whether it is under a Scaffold?

Viewed 60

App〈 MaterialApp〈 MyWidget : all is good

Whether I draw the figure on a canvas with a small or a large scale—by replacing v = 100000.0 with v = 1000.0 in the following code, the image doesn't change, as expected.

(If you are not familiar with the idea of using a SizedBox inside a FittedBox, it is explained here.)

scale invariant rendering

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

const v = 10000.0;

class Painter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final mypaint = Paint()
    ..style = PaintingStyle.stroke
    ..strokeWidth = 0.012 * v
    ..color = Colors.blue;

    canvas.drawCircle(
      Offset(1.5 * v, 1 * v),
      1 * v, mypaint);
  }

  @override
  bool shouldRepaint(Painter oldDelegate) => false;
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "My App",
      home: FittedBox(
        child: SizedBox(
          width: 3 * v,
          height: 2 * v,
          child: CustomPaint(
            painter: Painter()
            ),
        ),
      ),
    );
  }
}

App〈 Scaffold〈 MaterialApp〈 MyWidget : My chosen size in SizedBox is ignored; why?

But if I put MaterialApp inside a Scaffold, I still get the image on the left for v = 10000.0, but with v = 100.0, I get instead the image on the right.

image changes when scale is changed

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

const v = 10000.0;

class Painter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final mypaint = Paint()
    ..style = PaintingStyle.stroke
    ..strokeWidth = 0.012 * v
    ..color = Colors.blue;

    canvas.drawCircle(
      Offset(1.5 * v, 1 * v),
      1 * v, mypaint);
  }

  @override
  bool shouldRepaint(Painter oldDelegate) => false;
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "My App",
      home: Scaffold(
        appBar: AppBar(
          title: const Text('My Title'),
        ),
        body: FittedBox(
          child: SizedBox(
            width: 3 * v,
            height: 2 * v,
            child: CustomPaint(
              painter: Painter()
              ),
          ),
        ),
      ),
    );
  }
}

How do I get a scale invariant CustomPaint with a Scaffold?

1 Answers

The custom paint is independant of the size. It takes the size sent from it's caller. If you set the sizedbox's size to 200x200 it will paint in that space. Now 10k or 1k will give same result since there is no space left on the device to paint something since width of device is less than 1k. But 10, 100 and 1k will show different sized circles. The only factor that defines the scale here would be the size of the SizedBox

The draw circle can also be written as

canvas.drawCircle(Offset(size.height / 2, size.width / 2), size.width/2);

Now if you pass a sized box of 100x100 it will draw a circle of diameter 100

Related