Flutter CustomPaint and CustomPainter creating widget of incorrect size

67 views Asked by At

I have a program that creates a Pie-Chart using CustomPainter and CustomPaint that uses a SizedBox as the Canvas and is the Widget returned. However, the width of the SizedBox is being set to the Screen Width and not the width specified of “300”. This means that I cannot use the Widget created because it is the incorrect size. I created a test program that does virtually the same and it functions correctly. Both programs create a SizedBox of 300x300 however the problem program is setting the width to the screen width of 411. I have previously painted a completely different widget using similar details without any problems.

Perhaps someone can show me what I have done wrong because I cannot find it.

Details of the problem program and the test program are as follows:

Problem Program

import 'dart:math' as math;
import 'package:flutter/material.dart';
//
import '../classes/ClassPieChartParams.dart';

class PieChartComponent extends SizedBox {
  final double width;
  final double height;
  PieChartComponent(
      {required this.width,
      required this.height,
      required ClassPieChartParams clsPieChartParams})
      : super(
            child: CustomPaint(
                painter: PieChartPainter(
          clsPieChartParams: clsPieChartParams,
        )));
}

class PieChartPainter extends CustomPainter {
  final ClassPieChartParams clsPieChartParams;
  PieChartPainter({required this.clsPieChartParams});
  @override
  void paint(Canvas canvas, Size size) {
    //
    debugPrint(
        "\n\n****** At 44: paint: size.width = ${size.width}, size.height = ${size.height}\n");

This is called via the following:

      return PieChartComponent(
          clsPieChartParams: clsPieChartParams, width: 300, height: 300);

The debug output is as follows:

“****** At 44: paint: size.width = 411.42857142857144, size.height = 300.0” The width shown is the screen width.

Flutter Doctor

Flutter (Channel stable, 3.19.3, on Microsoft Windows [Version 10.0.22631.3296] • No issues found!

Test Program

I created a small test program that does virtually the same up to that point, and its debug output is:

Test Program Debug Output

****** At 27: Canvas01: sTest = Test String, paint: size.width = 300.0, size.height = 300.0

I can easily fix the size of what is painted, but the main problem is that the widget created is not the correct size and in any case I need to know what is causing the problem.

The test program is as follows:

class Canvas01 extends SizedBox {
  final double width;
  final double height;
  final String sTest;
  Canvas01({required this.width, required this.height, required this.sTest})
      : super(child: CustomPaint(painter: CanvasPainter(sTest)));
}

class CanvasPainter extends CustomPainter {
  final String sTest;
  CanvasPainter(this.sTest);
  //
  final wPainter1 = Paint()
    ..color = Colors.red
    ..strokeWidth = 2
    ..style = PaintingStyle.stroke;

  @override
  void paint(Canvas canvas, Size size) {
    debugPrint('''\n\n****** At 27: Canvas01: sTest = $sTest, paint:'''
        ''' size.width = ${size.width}, size.height = ${size.height}\n''');
    canvas.drawOval(Rect.fromLTWH(0, 0, size.width, size.height), wPainter1);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false; // DOES NOT CHANGE
  }
}

This is called via:

return Canvas01(width: 300, height: 300, sTest: 'Test String');

The widget for the test program is the correct size.

3

There are 3 answers

2
qinglie On

maybe you should check the constraint of child widget,which parent widget provider for

1
JaSaNi DiVyEsH On

Thank you for providing the code. From what you've shared, it seems like the PieChartComponent class is subclassing SizedBox and not utilizing its parameters properly. The SizedBox widget itself doesn't respect its own width and height parameters if it's a subclass. Instead, you should use those parameters to set the size of its child.

To fix the issue, you should set the width and height parameters of the SizedBox's child, which in this case is the CustomPaint widget. Here's how you can adjust your PieChartComponent class:

    class PieChartComponent extends StatelessWidget {
  final double width;
  final double height;
  final ClassPieChartParams clsPieChartParams;

  PieChartComponent({
    required this.width,
    required this.height,
    required this.clsPieChartParams,
  });

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: width,
      height: height,
      child: CustomPaint(
        size: Size(width, height), // Set size of CustomPaint
        painter: PieChartPainter(
          clsPieChartParams: clsPieChartParams,
        ),
      ),
    );
  }
}

In this modified version:

  • PieChartComponent is now a StatelessWidget instead of subclassing SizedBox.
  • The width and height parameters are passed to both the SizedBox and the CustomPaint.
  • Inside the SizedBox, the CustomPaint widget's size property is explicitly set to Size(width, height).

With this change, the CustomPaint will respect the specified width and height parameters, ensuring that your pie chart is drawn within a 300x300 area.

0
briano On

I haven't fully investigated the implementation of this, however by hard-coding the values and using clipRect, this appears to solve the problem. Just why it is necessary to do that I don't understand, and why it is not necessary in other cases I don't understand.

Current change is as follows:


class PieChartPainter extends CustomPainter {
  final ClassPieChartParams clsPieChartParams;
  PieChartPainter({required this.clsPieChartParams});
  @override
  void paint(Canvas canvas, size) {
    //
    Size wSize = Size(300, 300);
    canvas.clipRect(Offset.zero & wSize);

Obviously I need to implement the change without hard-coding it, which I will do later. It has taken a lot of hours to get to this, and it appears to solve the problem at this stage.

UPDATE 1

In order to illustrate what is happening, the following shows the latest changes I have made to this code. The obvious problem being why the width of the Extended SizedBox appears not to be set correctly.


import 'dart:math' as math;
import 'package:flutter/material.dart';
//
import '../classes/ClassPieChartParams.dart';

class PieChartComponent extends SizedBox {
  PieChartComponent(width, height, ClassPieChartParams clsPieChartParams)
      : super(
            width: width,
            height: height,
            child: CustomPaint(
                painter: PieChartPainter(
                    dWidth: width,
                    dHeight: height,
                    clsPieChartParams: clsPieChartParams)));
}

class PieChartPainter extends CustomPainter {
  final double dWidth;
  final double dHeight;
  final ClassPieChartParams clsPieChartParams;
  PieChartPainter(
      {required this.dWidth,
      required this.dHeight,
      required this.clsPieChartParams});
  @override
  void paint(Canvas canvas, size) async {
    //
    debugPrint(
        "\n\n****** At 35: paint: dWidth = $dWidth, dHeight = $dHeight\n");

    debugPrint(
        "\n\n****** At 38: paint: size.width = ${size.width}, size.height = ${size.height}\n");
    Size wSizeCanvas = Size(dWidth, dHeight);
    canvas.clipRect(Offset.zero & wSizeCanvas);
    debugPrint(
        "\n\n****** At 42: paint: size.width = ${size.width}, size.height = ${size.height}\n");


Debug Output

I/flutter ( 2026):
I/flutter ( 2026): ****** At 35: paint: dWidth = 300.0, dHeight = 300.0
I/flutter ( 2026):
I/flutter ( 2026):
I/flutter ( 2026):
I/flutter ( 2026): ****** At 38: paint: size.width =
                   411.42857142857144, size.height = 300.0
I/flutter ( 2026):
I/flutter ( 2026):
I/flutter ( 2026):
I/flutter ( 2026): ****** At 42: paint: size.width = 
                   411.42857142857144, size.height = 300.0
I/flutter ( 2026):