Flutter CustomPaint better antialiasing - flutter

Paint.isAntiAlias = false;
Paint.isAntiAlias = true;
#override
void paint(Canvas canvas, Size size) {
final Path path_0 = Path();
path_0.moveTo(
size.width * 0.5002533,
size.height * 0.004880920,
);
path_0.cubicTo(
size.width * 0.2252237,
size.height * 0.004880922,
size.width * 0.002532500,
size.height * 0.2268787,
size.width * 0.002532500,
size.height * 0.5010510,
);
path_0.cubicTo(
size.width * 0.002532500,
size.height * 0.7752251,
size.width * 0.2252237,
size.height * 0.9972229,
size.width * 0.5002533,
size.height * 0.9972220,
);
path_0.cubicTo(
size.width * 0.7752828,
size.height * 0.9972229,
size.width * 0.9979740,
size.height * 0.7752251,
size.width * 0.9979740,
size.height * 0.5010510,
);
path_0.cubicTo(
size.width * 0.9979740,
size.height * 0.2268787,
size.width * 0.7752828,
size.height * 0.004880922,
size.width * 0.5002533,
size.height * 0.004880920,
);
path_0.close();
path_0.moveTo(
size.width * 0.5002533,
size.height * 0.8731800,
);
path_0.cubicTo(
size.width * 0.3693230,
size.height * 0.8731802,
size.width * 0.2513929,
size.height * 0.7020954,
size.width * 0.2513929,
size.height * 0.5010510,
);
path_0.cubicTo(
size.width * 0.2513929,
size.height * 0.3000084,
size.width * 0.3692386,
size.height * 0.1289237,
size.width * 0.5002533,
size.height * 0.1289230,
);
path_0.cubicTo(
size.width * 0.6312679,
size.height * 0.1289237,
size.width * 0.7491136,
size.height * 0.3000084,
size.width * 0.7491136,
size.height * 0.5010510,
);
path_0.cubicTo(
size.width * 0.7491136,
size.height * 0.7020954,
size.width * 0.6311835,
size.height * 0.8731802,
size.width * 0.5002533,
size.height * 0.8731800,
);
path_0.close();
final Paint paint0Fill = Paint()..style = PaintingStyle.fill;
paint0Fill.color = colors['kMainColor']!;
canvas.drawPath(path_0, paint0Fill);
final Path path_1 = Path();
path_1.moveTo(
size.width * 0.8129326,
size.height * 0.1151220,
);
path_1.cubicTo(
size.width * 0.7594125,
size.height * 0.07859968,
size.width * 0.6966064,
size.height * 0.05444753,
size.width * 0.6312679,
size.height * 0.05444750,
);
path_1.cubicTo(
size.width * 0.5330069,
size.height * 0.05444753,
size.width * 0.4440317,
size.height * 0.1035934,
size.width * 0.3782711,
size.height * 0.1804250,
);
path_1.cubicTo(
size.width * 0.4149924,
size.height * 0.1479424,
size.width * 0.4568631,
size.height * 0.1288395,
size.width * 0.5002533,
size.height * 0.1288390,
);
path_1.cubicTo(
size.width * 0.6311835,
size.height * 0.1288395,
size.width * 0.7491136,
size.height * 0.2999243,
size.width * 0.7491136,
size.height * 0.5009670,
);
path_1.cubicTo(
size.width * 0.7491136,
size.height * 0.7020113,
size.width * 0.6312679,
size.height * 0.8730960,
size.width * 0.5002533,
size.height * 0.8730960,
);
path_1.cubicTo(
size.width * 0.4568631,
size.height * 0.8730960,
size.width * 0.4149924,
size.height * 0.8539931,
size.width * 0.3782711,
size.height * 0.8215090,
);
path_1.cubicTo(
size.width * 0.4440317,
size.height * 0.8984263,
size.width * 0.5330069,
size.height * 0.9474880,
size.width * 0.6312679,
size.height * 0.9474880,
);
path_1.cubicTo(
size.width * 0.6966064,
size.height * 0.9474880,
size.width * 0.7594125,
size.height * 0.9233359,
size.width * 0.8129326,
size.height * 0.8868970,
);
path_1.cubicTo(
size.width * 0.9257977,
size.height * 0.7960111,
size.width * 0.9979740,
size.height * 0.6569890,
size.width * 0.9979740,
size.height * 0.5009670,
);
path_1.cubicTo(
size.width * 0.9979740,
size.height * 0.3450307,
size.width * 0.9257133,
size.height * 0.2060927,
size.width * 0.8129326,
size.height * 0.1151220,
);
path_1.close();
final Paint paint1Fill = Paint()..style = PaintingStyle.fill;
paint1Fill.color = AppTheme.darken(colors['kMainColor']!);
canvas.drawPath(path_1, paint1Fill);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
Is there any way to antialias canvas path(not image) better? If it was an image i'd use filterQuality but it's not an image. I think this should be possible.
Read article about this thing on Android, but did not find a way to use bitmap in Flutter's CustomPaint
I expect to get a result that looks like this:

Related

How to fill a line depending on a percentage using Canvas in Flutter?

I have a map that displays markers with data. On the right side of the marker there is an indicator in the form of a purple stripe. I need to make this indicator dynamic so that I can set a value in % and, depending on this value, the bar is filled with red. If the value is 100% then a completely red stripe, if 60% then a little more than half of the red color and the rest is green. I was drawing a strip using Canvas, but now I'm facing the problem that I don't know how can I make this strip dynamic, two-colored and dependent on %? I will be grateful for help
class PointPainter extends CustomPainter {
PointPainter({this.isClosed = false});
final bool isClosed;
#override
void paint(Canvas canvas, Size size) {
final strokeWidthThin = size.width * 0.07;
Paint paintMain = Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidthThin
..color = constants.Colors.purpleMain;
Paint paintPurpleThin = Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidthThin
..color = constants.Colors.purpleMain;
Paint paintPurpleBold = Paint()
..style = PaintingStyle.stroke
..strokeWidth = size.width * 0.16
..color = constants.Colors.purpleMain;
Paint paintGreen = Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidthThin
..color = constants.Colors.purpleMainDark.withOpacity(isClosed ? 0.5 : 1);
Paint paintTransparent = Paint()
..style = PaintingStyle.stroke
..strokeWidth = size.width * 0.04
..color = constants.Colors.purpleMainDark;
final pathMain = Path()
..moveTo(size.width / 2, size.height * 1.05)
..lineTo(size.width / 2 - size.width * 0.3, size.height * 0.4)
..arcToPoint(
Offset(size.width - size.width * 0.2, size.height * 0.3),
clockwise: true,
radius: const Radius.circular(0.9),
)
..lineTo(size.width / 2 + size.width * 0.3, size.height * 0.4);
final pathGreen = Path()
..moveTo(size.width / 2 + size.width * 0.3, size.height * 0.4)
..lineTo(size.width / 2, size.height)
..arcToPoint(
Offset(size.width - size.width * 0.22, size.height * 0.26),
clockwise: true,
radius: const Radius.circular(0.9),
);
final pathPurpleThin = Path()
..moveTo(size.width / 2, size.height * 1.05)
..lineTo(size.width / 2 - size.width * 0.3, size.height * 0.4);
final pathPurpleBold = Path()
..moveTo(size.width * 0.54, size.height * 1.03)
..lineTo(size.width / 2 + size.width * 0.3, size.height * 0.45);
final pathTransparent = Path()
..moveTo(size.width * 0.44, size.height)
..lineTo(size.width * 0.58, size.height * 0.68);
pathMain.close();
pathGreen.close();
pathPurpleThin.close();
pathTransparent.close();
if (!isClosed) {
canvas.drawPath(pathMain, paintMain);
canvas.drawPath(pathGreen, paintGreen);
canvas.drawPath(pathPurpleThin, paintPurpleThin);
canvas.drawPath(pathTransparent, paintTransparent);
}
canvas.drawPath(pathPurpleBold, paintPurpleBold);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
body
ClipPath(
clipper: PointClipper(),
child: Container(
width: width,
height: height,
color: constants.Colors.purpleMainDark,
child: CustomPaint(
painter: PointPainter(isClosed: isClosed),
),
),
),
point_clipper
class PointClipper extends CustomClipper<Path> {
PointClipper();
#override
Path getClip(Size size) {
//top
final path0 = Path();
path0..moveTo(size.width / 2, size.height * 0.4)
..lineTo(size.width / 2 - size.width * 0.3, size.height * 0.4)
..arcToPoint(
Offset(size.width - size.width * 0.2, size.height * 0.3),
clockwise: true,
radius: const Radius.circular(0.9),
)
..lineTo(size.width / 2 + size.width * 0.3, size.height * 0.4);
path0.close();
//bottom
path0.moveTo(size.width * 0.43, size.height * 0.9);
path0.quadraticBezierTo(size.width * 0.5, size.height * 1.1,
size.width * 0.57, size.height * 0.9);
path0.quadraticBezierTo(size.width * 0.6, size.height * 0.9,
size.width * 0.43, size.height * 0.9);
path0.close();
//middle
path0..moveTo(size.width * 0.43, size.height * 0.9)
..lineTo(size.width * 0.57, size.height * 0.9)
..lineTo(size.width / 2 + size.width * 0.3, size.height * 0.4)
..lineTo(size.width / 2 - size.width * 0.3, size.height * 0.4);
path0.close();
return path0;
}
#override
bool shouldReclip(PointClipper oldClipper) => true;
}

How to draw Image Inside Circulr path in Canvas in Flutter

Hello can anyone tell me how can i draw image inside circular path with scaled image that fits inside the path. I tried but could not able to figure out and bothering a lot. Please help me.
Paint paint_4 = new Paint()
..color = Colors.black
..style = PaintingStyle.fill
..strokeWidth = 1;
Path path_4 = Path();
path_4.moveTo(size.width * 0.2275000, size.height * 0.2879286);
path_4.cubicTo(
size.width * 0.2528667,
size.height * 0.2879286,
size.width * 0.2928750,
size.height * 0.3193143,
size.width * 0.2928750,
size.height * 0.4000000);
path_4.cubicTo(
size.width * 0.2928750,
size.height * 0.4449143,
size.width * 0.2733667,
size.height * 0.5120714,
size.width * 0.2275000,
size.height * 0.5120714);
path_4.cubicTo(
size.width * 0.2013083,
size.height * 0.5120714,
size.width * 0.1621250,
size.height * 0.4786286,
size.width * 0.1621250,
size.height * 0.4000000);
path_4.cubicTo(
size.width * 0.1621250,
size.height * 0.3550857,
size.width * 0.1808750,
size.height * 0.2879286,
size.width * 0.2275000,
size.height * 0.2879286);
path_4.close();
Circular Path to draw Image and Image need to be properly Scaled to
be visible
How Can I Scale assest image to Circular path in properly visibe or fit
How can i use Matrix4 to scale ImageShader to canvas
canvas.drawPath(
path_4,
Paint()
..shader = ImageShader(images, TileMode.clamp,TileMode.clamp,Matrix4.identity().scaled(0.19, 0.21).storage));
Here Is my Code
class ImagePainters extends StatefulWidget {
#override
_ImagePaintersState createState() => _ImagePaintersState();
}
class _ImagePaintersState extends State<ImagePainters> {
ui.Image myImage;
Future<ui.Image> _loadAssetImage() async {
Completer<ui.Image> completer = new Completer<ui.Image();
AssetImage('assets/face.jpg').resolve(new ImageConfiguration()).addListener(
ImageStreamListener((ImageInfo image, bool synchronousCall) {
setState(() {
myImage = image.image;
});
ui.Image img;
img = image.image;
completer.complete(img);
}));
return completer.future;
}
#override
void initState() {
super.initState();
_loadAssetImage();
}
#override
Widget build(BuildContext context) {
return Center(
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: CustomPaint(
size: Size(1000, 1000 * 0.7),
painter: FinalPainter(context, myImage)),
),
);
}
}
Canvas Drawing Class
class FinalPainter extends CustomPainter {
final ui.Image images;
FinalPainter(BuildContext context, this.images);
#override
void paint(Canvas canvas, Size size) {
Paint paint_4 = new Paint()
..color = Colors.black //Color.fromARGB(255, 255, 255, 255)
..style = PaintingStyle.fill
..strokeWidth = 1;
Path path_4 = Path();
path_4.moveTo(size.width * 0.2275000, size.height * 0.2879286);
path_4.cubicTo(
size.width * 0.2528667,
size.height * 0.2879286,
size.width * 0.2928750,
size.height * 0.3193143,
size.width * 0.2928750,
size.height * 0.4000000);
path_4.cubicTo(
size.width * 0.2928750,
size.height * 0.4449143,
size.width * 0.2733667,
size.height * 0.5120714,
size.width * 0.2275000,
size.height * 0.5120714);
path_4.cubicTo(
size.width * 0.2013083,
size.height * 0.5120714,
size.width * 0.1621250,
size.height * 0.4786286,
size.width * 0.1621250,
size.height * 0.4000000);
path_4.cubicTo(
size.width * 0.1621250,
size.height * 0.3550857,
size.width * 0.1808750,
size.height * 0.2879286,
size.width * 0.2275000,
size.height * 0.2879286);
path_4.close();
Image should be properly visible and can be scaled Circular Path to
draw Image and Image need to be properly Scaled to be visible
Face should be visible clearly inside the circular path
canvas.drawPath(path_4, Paint()..shader = ImageShader(images,
TileMode.clamp, TileMode.clamp,
Matrix4.identity().scaled(0.19, 0.21).storage));}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
{return true;}
}

How to create an inner shadow for custom shape in Flutter?

Below is the custom shape I've want to give an inner shadow to :
Below is the code I've used to create this shape : (The text part is not included in the code)
class TitleContainerPaint extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
Paint x = Paint()..color = Colors.grey ..style = PaintingStyle.fill;
Path a = Path();
a.moveTo(size.height * 0.5, 0);
a.lineTo(size.width * 0.3, 0);
a.cubicTo(size.width * 0.325, 0, size.width * 0.325, size.height * 0.5 - 10, size.width * 0.35, size.height * 0.5 - 10);
a.lineTo(size.width * 0.825, size.height * 0.35);
a.cubicTo(size.width * 0.85, size.height * 0.5 - 10, size.width * 0.85, size.height * 0.15, size.width * 0.875, size.height * 0.15);
a.lineTo(size.width - size.height * 0.25, size.height * 0.15);
a.arcTo(Rect.fromCircle(center: Offset(size.width - size.height * 0.35,size.height * 0.5), radius: size.height * 0.35), -pi/2, pi, false);
a.lineTo(size.width * 0.875, size.height * 0.85);
a.cubicTo(size.width * 0.85, size.height * 0.85, size.width * 0.85, size.height * 0.5 + 10, size.width * 0.825, size.height * 0.5 + 10);
a.lineTo(size.width * 0.35, size.height * 0.65);
a.cubicTo(size.width * 0.325, size.height * 0.5 + 10, size.width * 0.325, size.height, size.width * 0.3, size.height);
a.lineTo(size.height * 0.5, size.height);
a.arcTo(Rect.fromCircle(center: Offset(size.height * 0.5,size.height * 0.5), radius: size.height * 0.5), pi/2, pi, false);
canvas.drawPath(a, x);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
}
As mentioned in the question, my goal is to add an inner shadow to this shape like the image below :
Can someone please help me achieve this?
Thankyou in advance.
Use your paint like this:
Paint x = Paint()
..style = PaintingStyle.fill
..maskFilter = MaskFilter.blur(BlurStyle.inner, 5)
..color = Colors.grey;
Output:
I propose the same approach as given in my other answer. In your case you just use the CustomPaint widget as the child for the inner shadow widget:
InnerShadow(
shadow: const BoxShadow(
blurRadius: 20,
color: Colors.black,
),
child: CustomPaint(painter: TitleContainerPaint()),
)
The complete code could be found here https://codepen.io/priezz/pen/abBRmrb
P.S. Your TitleContainerPaint gives slightly different shape than given in your example image, you'll probably need to tweak it. Maybe it's just the issue with Flutter for Web.
//change the alpha color of your grey color like this
canvas.drawShadow(path, Colors.grey.withAlpha(50), -4.0, false);
Here the shadow will be inner.

Paint shape with flutter customPainter widget

How i can paint something like this in flutter with CustomPainter:
image
Try this and tweak the values to your convenience
class CurvedBarPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.black;
Path path = Path();
path.lineTo(0.0, size.height * .58);
path.quadraticBezierTo(size.width * .01, size.height * .95 , size.width * .15, size.height);
path.lineTo(size.width * .85, size.height);
path.quadraticBezierTo(size.width * .99, size.height * .95 , size.width, size.height * .6);
path.lineTo(size.width, size.height * .2);
path.quadraticBezierTo(size.width * .99, size.height * -.02, size.width * .9, 0.0);
path.lineTo(size.width * .8, 0.0);
path.quadraticBezierTo(size.width * .7, size.height * .01, size.width * .65, size.height * .3);
path.quadraticBezierTo(size.width * .5, size.height , size.width * .35, size.height * .3);
path.quadraticBezierTo(size.width * .3, size.height * .01, size.width * .2, 0.0);
path.lineTo(size.width * .1, 0.0);
path.quadraticBezierTo(size.width * .01, size.height * -.02, 0.0, size.height * .2);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}

Draw Custom shape Flutter

I'm trying to draw the shape in this image
The shape that I want to draw
Put I can't get the same result by my code :
CustomShapeClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
final Path path = Path()
..moveTo(0, size.height * 0.6)
..quadraticBezierTo(
size.width * 0.7 , size.height - (size.height * 0.1) ,
size.width, size.height * 0.8
)
..lineTo(size.width, 0)
..lineTo(0, 0)
..close();
return path;
}
#override
bool shouldReclip(CustomClipper oldClipper) => true;
}
I get this result My Result
Kindly guide me for this.
Thanks in advance
I managed to draw something similar using cubicTo instead of quadraticBezierTo. A simple example for what you need:
final Path path = Path()
..moveTo(0, size.height * 0.6)
..lineTo(size.width * 0.7 - (size.width * 0.05),
size.height - 2 * (size.height * 0.1))
..cubicTo(
size.width * 0.7 - (size.width * 0.01),
size.height - 1.88 * (size.height * 0.1),
size.width * 0.7 + (size.width * 0.01),
size.height - 1.88 * (size.height * 0.1),
size.width * 0.7 + (size.width * 0.05),
size.height - 2 * (size.height * 0.1))
..lineTo(size.width, size.height * 0.7)
..lineTo(size.width, 0)
..lineTo(0, 0)
..close();
I know that there are a lot of numbers, but you can extract some points as separate variables for a better readability.
Practically instead of drawing a Quadric Bezier, we draw 2 lines and the curve between them.
Also you can add clipBehavior: Clip.antiAliasWithSaveLayer to your ClipPath for a smooth drawing
Try this and let me know if it works for you.
In your widget body you can have a build method looking similar to this
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
ClipPath(
clipper: BottomEndClipper(),
child: Container(
height: MediaQuery.of(context).size.height * .5,
decoration: BoxDecoration(
//Your gradient or own color
color: Colors.purple,
),
),
),
],
),
);
}
}
And your custom clipper looking like this
class BottomEndClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, size.height - 80);
path.lineTo(size.width * .7, size.height - 10);
path.quadraticBezierTo(
size.width * .8, size.height, size.width * .95, size.height * .90);
path.lineTo(size.width, size.height*.87);
path.lineTo(size.width, 0);
path.close();
return path;
}
//Should return false if you don't wish to redraw every time
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}