How do I get rounded corners in CustomPaint with fill in Flutter?

Issue

I have a custom paint as below:

class _MPButtonPainter extends CustomPainter {
  final Color fillColor;
  final bool reverse;

  _MPButtonPainter({
    required this.fillColor,
    required this.reverse,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      // parametrize
      ..color = fillColor
      ..style = PaintingStyle.fill;

    // const a = Offset(0, 0);
    // final b = Offset(size.width, size.height);
    // final rect = Rect.fromPoints(a, b);

    final path = Path()
      // parametrize
      ..lineTo(0, 0)
      ..lineTo(size.width, 0)
      ..arcToPoint(
        Offset(size.width, size.height),
        radius: reverse ? const Radius.circular(35) : const Radius.circular(5),
        clockwise: !reverse,
      )
      ..lineTo(0, size.height)
      ..arcToPoint(
        Offset.zero,
        radius: reverse ? const Radius.circular(5) : const Radius.circular(35),
        clockwise: reverse,
      )
      ..close();

    canvas.drawPath(path, paint);
  }

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

…which draws the shapes below:

mpbutton shape irl

However, my goal is to achieve below:

mpbutton mockup

As you can see, this design has rounded corners at the end rather than being sharp.

I have tingled with strokeCap param on Paint, but it only affects strokes. This shape has fills. I wonder how I can achieve rounded corners.

Thanks in advance.

Environment

> flutter doctor -v
[✓] Flutter (Channel stable, 2.10.3, on KDE neon User - 5.24 5.13.0-39-generic, locale en_US.UTF-8)
    • Flutter version 2.10.3 at /home/erayerdin/snap/flutter/common/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 7e9793dee1 (4 weeks ago), 2022-03-02 11:23:12 -0600
    • Engine revision bd539267b4
    • Dart version 2.16.1
    • DevTools version 2.9.2

[✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
    • Android SDK at /opt/sdks/android/
    • Platform android-32, build-tools 32.1.0-rc1
    • Java binary at: /snap/android-studio/current/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Android Studio (version 2021.1)
    • Android Studio at /snap/android-studio/119/android-studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)

[✓] Android Studio
    • Android Studio at /snap/android-studio/current/android-studio/
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • android-studio-dir = /snap/android-studio/current/android-studio/
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)

[✓] VS Code
    • VS Code at /snap/code/current
    • Flutter extension version 3.36.0

[✓] Connected device (2 available)
    • AOSP on IA Emulator (mobile) • emulator-5554 • android-x86    • Android 9 (API 28) (emulator)
    • Chrome (web)                 • chrome        • web-javascript • Google Chrome 100.0.4896.60

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

Solution

My proposal is to use quadraticBezierTo for each corner. You can pass littleGap value for corner changes, though this is not perfect, but hope it can be done using quadraticBezierTo and cubicTo .

enter image description here


class _MPButtonPainter extends CustomPainter {
  final Color fillColor;
  final double littleGap;

  _MPButtonPainter({
    required this.fillColor,
    this.littleGap = 5,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      // parametrize
      ..color = fillColor
      ..style = PaintingStyle.fill;

    final path = Path()
      // parametrize
      ..moveTo(littleGap, 0)
      ..lineTo(size.width * .8, 0)
      //main right curve:
      ..cubicTo(
        size.width * 1,
        0,
        size.width * 1,
        size.height,
        size.width * .8,
        size.height,
      )
      ..lineTo(littleGap, size.height)

      //bottom corner
      ..quadraticBezierTo(
        littleGap / 2,
        size.height - (littleGap / 2),
        littleGap,
        size.height - littleGap,
      )

      ///middle hole
      ..quadraticBezierTo(
        size.width * .2,
        size.height / 2,
        littleGap,
        littleGap,
      )

      //top corner
      ..quadraticBezierTo(
        littleGap / 2,
        littleGap / 2,
        littleGap,
        0,
      )
      ..close();

    canvas.drawPath(path, paint);
  }

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

And hope you can handle the reverse one.

Answered By – Yeasin Sheikh

Answer Checked By – Jay B. (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.