Issue
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:
Solution
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
Answered By - Thracian
Answer Checked By - Candace Johnson (JavaFixing Volunteer)