Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert flutter painter to compose

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

like image 383
Captivity Avatar asked Mar 29 '26 18:03

Captivity


1 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

like image 148
Thracian Avatar answered Mar 31 '26 10:03

Thracian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!