Convert flutter painter to compose

Viewed 117

I have code in flutter and I have to write an app in android (kotlin). How can I convert flutter painter to display in android compose?

import 'dart:math' as math;
import 'dart:ui' as ui;

import 'package:flutter/material.dart';

class FaceOutline extends CustomPainter {
  final Color frameColor;

  FaceOutline(this.frameColor);

  @override
  void paint(ui.Canvas canvas, ui.Size size) {
    final Path path = Path();
    final Rect rect = Rect.fromCenter(
      center: size.center(Offset.zero),
      width: size.width * 0.95,
      height: size.width * 0.95,
    );

    path.addArc(
      rect.translate(0.0, -rect.height * 0.4),
      math.pi * 9.0 / 8.0,
      math.pi * 2.0 / 8.0,
    );
    path.addArc(
      rect.translate(0.0, -rect.height * 0.4),
      math.pi * 13.0 / 8.0,
      math.pi * 2.0 / 8.0,
    );
    path.addArc(
      rect.translate(0.0, rect.height * 0.00),
      math.pi * 1.0 / 8.0,
      math.pi * 2.0 / 8.0,
    );
    path.addArc(
      rect.translate(0.0, rect.height * 0.00),
      math.pi * 5.0 / 8.0,
      math.pi * 2.0 / 8.0,
    );

    canvas.drawPath(
      path,
      Paint()
        ..filterQuality = FilterQuality.low
        ..isAntiAlias = true
        ..strokeWidth = 8
        ..strokeCap = StrokeCap.round
        ..strokeJoin = StrokeJoin.round
        ..style = PaintingStyle.stroke
        ..color = frameColor
        ..blendMode = BlendMode.screen,
    );
  }

  @override
  bool shouldRepaint(FaceOutline oldDelegate) {
    return frameColor != oldDelegate.frameColor;
  }
}

I can use xml or compose to display it in kotlin but I have to know how can I write that flutter's code in native android in Compose view.

You can check code: https://dartpad.dev/?id=b426645ba864beaa66d18212128a71cd

It's what I want to have:

enter image description here

2 Answers

Jetpack Compose Canvas counterpart of this is as below

Things to note. Path is inside remember to not create a new instance on any recompositions and we set path once when it's empty

If BlendMode is needed to apply we should either set alpha of Canvas less than 1f or use a layer as in this answer

@Composable
private fun FaceOutlineComposable(modifier: Modifier, frameColor: Color) {

    val path = remember { Path() }

    Canvas(modifier = modifier) {

        if (path.isEmpty) {

            val canvasWidth = size.width
            val canvasHeight = size.height
            val width = size.width * 0.95f

            val rect = Rect(
                offset = Offset((canvasWidth - width) / 2, (canvasHeight - width) / 2),
                size = Size(width, width)
            )

            path.apply {
                addArcRad(
                    rect.translate(0.0f, -rect.height * 0.4f),
                    (Math.PI * 9.0 / 8.0).toFloat(),
                    (Math.PI * 2.0 / 8.0).toFloat(),
                )
                addArcRad(
                    rect.translate(0.0f, -rect.height * 0.4f),
                    (Math.PI * 13.0 / 8.0).toFloat(),
                    (Math.PI * 2.0 / 8.0).toFloat(),
                )
                addArcRad(
                    rect,
                    (Math.PI * 1.0 / 8.0).toFloat(),
                    (Math.PI * 2.0 / 8.0).toFloat(),
                )
                addArcRad(
                    rect,
                    (Math.PI * 5.0 / 8.0).toFloat(),
                    (Math.PI * 2.0 / 8.0).toFloat(),
                )
            }
        }
        
        // This is for applying blend modes
        with(drawContext.canvas.nativeCanvas) {
            val checkPoint = saveLayer(null, null)

            drawPath(
                path = path,
                color = frameColor,
                style = Stroke(
                    width = 8.dp.toPx(),
                    cap = StrokeCap.Round,
                    join = StrokeJoin.Round
                ),
                blendMode = BlendMode.Screen
            )

            restoreToCount(checkPoint)
        }
    }
}

Usage

FaceOutlineComposable(
    modifier = Modifier
        .fillMaxSize()
        .background(Color(0xff12252a)),
    frameColor = Color(0xff2196F3)
)

Result

Short answer : There is no converter Flutter <-> Android. You'll have to re-write it yourself.


Long answer :
What you're asking is to convert a specific Language (Dart) with specific Framework methods (Flutter) to another Language (Kotlin) working with another SDK (Android).
This is not possible unless you find someone mad enough to map every function of both language/framework and who publishes this converter online.

You'll have to re-develop it yourself either by :

  • Doing it with Jetpack Compose (if you worked a lot with Flutter, it'll be simple enough to learn)
  • Creating a view from scratch with a ConstraintLayout (which is easier to handle than the basic LinearLayout/RelativeLayout combos)
  • Displaying a Canvas in your view, and drawing on it with the Paint object.
    I think this solution is the best for you since a lot of methods are quite alike between Flutter and Android. See the example below
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    canvas.apply {
        // Draw the shadow
        drawOval(shadowBounds, shadowPaint)

        // Draw the label text
        drawText(data[mCurrentItem].mLabel, textX, textY, textPaint)

        // Draw the pie slices
        data.forEach {
            piePaint.shader = it.mShader
            drawArc(bounds,
                    360 - it.endAngle,
                    it.endAngle - it.startAngle,
                    true, piePaint)
        }

        // Draw the pointer
        drawLine(textX, pointerY, pointerX, pointerY, textPaint)
        drawCircle(pointerX, pointerY, pointerSize, mTextPaint)
    }
}

Documentation is here

Related