Battery level indicator drawing upside down in Flutter CustomPainter Class

Issue

I have this code to draw the battery level but it is drawing the inside colored indicator from the top down. It should paint it from the bottom to the top like you see on all Android phones. Any thoughts on what I am doing wrong?

class BatteryLevelPainter extends CustomPainter {
  final int _batteryLevel;
  final BatteryState _batteryState;

  BatteryLevelPainter(this._batteryLevel, this._batteryState);

  @override
  void paint(Canvas canvas, Size size) {
    Paint getPaint({Color color = Colors.black, PaintingStyle style = PaintingStyle.stroke}) {
      return Paint()
        ..color = color
        ..strokeWidth = 1.0
        ..style = style;
    }

    final RRect batteryOutline = RRect.fromLTRBR(0.0, 0.0, size.width, size.height, const Radius.circular(2.0));

    // Battery body
    canvas.drawRRect(
      batteryOutline,
      getPaint(),
    );

    // Battery nub
    canvas.drawRect(
      const Rect.fromLTWH(4.0, -3.0, 4.0, 3.0),
      getPaint(style: PaintingStyle.fill),
    );

    // Fill rect
    canvas.clipRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height * (_batteryLevel / 100)));

    Color indicatorColor;

    if (_batteryLevel < 15) {
      indicatorColor = Colors.red;
    } else if (_batteryLevel < 30) {
      indicatorColor = Colors.orange;
    } else {
      indicatorColor = Colors.green;
    }

    canvas.drawRRect(
      RRect.fromLTRBR(0.5, 0.5, size.width - 0.5, size.height - 0.5, const Radius.circular(2.0)),
      getPaint(style: PaintingStyle.fill, color: indicatorColor),
    );
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    final BatteryLevelPainter old = oldDelegate as BatteryLevelPainter;

    return old._batteryLevel != _batteryLevel || old._batteryState != _batteryState;
  }
}

Battery Level Indicator

Solution

Use Rect.fromLTRB() instead of Rect.fromLTWH(). Or you can use Rect.fromCircle() or Rect.fromCenter() or Rect.fromPoints(). Rect class

Add this line:

canvas.translate(0.0, (size.height - size.height * (_batteryLevel / 100)));

The complete code:

class BatteryLevelPainter extends CustomPainter {
  final int _batteryLevel;
  final BatteryState _batteryState;

  BatteryLevelPainter(this._batteryLevel, this._batteryState);

  @override
  void paint(Canvas canvas, Size size) {
    Paint getPaint({Color color = Colors.black, PaintingStyle style = PaintingStyle.stroke}) {
      return Paint()
        ..color = color
        ..strokeWidth = 1.0
        ..style = style;
    }

    final RRect batteryOutline = RRect.fromLTRBR(0.0, 0.0, size.width, size.height, const Radius.circular(2.0));

    // Battery body
    canvas.drawRRect(
      batteryOutline,
      getPaint(),
    );

     canvas.translate(0.0, (size.height - size.height * (_batteryLevel / 100))); // add this line

    // Battery nub
    canvas.drawRect(
      const Rect.fromLTWH(4.0, -3.0, 4.0, 3.0),
      getPaint(style: PaintingStyle.fill),
    );

    // Fill rect
    canvas.clipRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height * (_batteryLevel / 100)));

    Color indicatorColor;

    if (_batteryLevel < 15) {
      indicatorColor = Colors.red;
    } else if (_batteryLevel < 30) {
      indicatorColor = Colors.orange;
    } else {
      indicatorColor = Colors.green;
    }

    canvas.drawRRect(
      RRect.fromLTRBR(0.5, 0.5, size.width - 0.5, size.height - 0.5, const Radius.circular(2.0)),
      getPaint(style: PaintingStyle.fill, color: indicatorColor),
    );
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    final BatteryLevelPainter old = oldDelegate as BatteryLevelPainter;

    return old._batteryLevel != _batteryLevel || old._batteryState != _batteryState;
  }
}

Answered By – Mouaz M Shahmeh

Answer Checked By – Marilyn (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *