Flutter canvas drawing lines without overlay effect - flutter

In flutter canvas if you try to draw two lines one above the other on the overlap the result line becomes larger. Below the code and an image with the result.
class MyPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
canvas.drawLine(const Offset(100, 100), const Offset(200, 200), Paint());
canvas.drawLine(const Offset(100, 100), const Offset(400, 400), Paint());
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
Line overlap
I hope it can be visible because the difference is very little.
In the project I'm working in, I don't want this to happen. Any suggestions?
Thank you very much

Related

Flutter Custom Shape

I need to make a shape as seen in the photo below with container in Flutter, can you help me for this?
use this code to create shape like this
import 'dart:ui' as ui;
//Add this CustomPaint widget to the Widget Tree
CustomPaint(
size: Size(WIDTH, (WIDTH*0.3542581280172481).toDouble()), //You can Replace [WIDTH] with your desired width for Custom Paint and height will be calculated automatically
painter: RPSCustomPainter(),
)
//Copy this CustomPainter code to the Bottom of the File
class RPSCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Path path_0 = Path();
path_0.moveTo(size.width*1.156952,size.height*3.936736);
path_0.lineTo(size.width*1.968605,size.height*3.949394);
path_0.cubicTo(size.width*1.968605,size.height*3.949394,size.width*2.151398,size.height*4.204300,size.width*2.152460,size.height*4.443043);
path_0.cubicTo(size.width*2.153491,size.height*4.675744,size.width*1.977573,size.height*4.936736,size.width*1.977573,size.height*4.936736);
path_0.lineTo(size.width*1.152468,size.height*4.898765);
path_0.lineTo(size.width*1.156952,size.height*3.936736);
path_0.close();
Paint paint_0_fill = Paint()..style=PaintingStyle.fill;
paint_0_fill.color = Color.fromRGBO(216, 216, 216,1.0).withOpacity(1.0);
canvas.drawPath(path_0,paint_0_fill);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}

How draw a rectangle directly on an image in flutter

I want to draw a rectangle on the actual image and don't want to use the flutter renderer to add a rectangle on the top layer just as a view. I can get the pixel color, but how can I overwrite the bonch of pixels?
ByteData byteData = await rootBundle.load('assets/images/maps/map.jpg');
Uint8List bytes = byteData.buffer.asUint8List();
List<int> values = bytes;
img.Image photo = img.decodeImage(values)!;
final pixels = photo.getBytes(format: img.Format.rgba);
I´m not quite sure, if this is the answer you need, but what about using a Stack?
Stack(children: [
image,
Positioned.fill(
child: CustomPaint(
painter: Sky(r),
child: Container()));
}),
],
)
...
class Sky extends CustomPainter {
Rect rect;
Sky(this.rect);
#override
void paint(Canvas canvas, Size size) {
canvas.drawRect(rect, Paint()..color = Colors.black);
}
#override
bool shouldRepaint(Sky oldDelegate) => false;
}

CustomPainter: How to draw translucent areas?

This sketch shows what the final result should look like:
A CustomPainter fills its Canvas (yellow area) with a slightly translucent background color. (Amber with an opacity of 0.8 in the sketch).
The CustomPainter draws a rectangle onto the canvas. And here it's getting interesting: The rectangle should only change the alpha value of the background color drawn at the previous step. The idea is to highlight some points of interest, by fading some "holes" in and out (visualized by the smaller, darker rectangle inside the yellow rectangle in the sketch above).
In code it looks simple:
class Highlighter extends CustomPainter {
ValueListenable<double> valueListenable;
Color backgroundColor;
Highlighter({required this.valueListenable, this.backgroundColor = Colors.amber}) : super(repaint: valueListenable);
#override
void paint(Canvas canvas, Size size) {
Color colorHole = backgroundColor.withOpacity(0.40);
Paint holePainter = Paint();
holePainter.color = colorHole;
holePainter.blendMode = BlendMode.dstOut;
canvas.saveLayer(null, holePainter);
// Step 1: Draw the background:
canvas.drawColor(backgroundColor.withOpacity(0.80), BlendMode.srcOver);
// Step 2: Highlight a rectangle:
canvas.drawRect(const Rect.fromLTWH(100, 100, 100, 100), holePainter);
canvas.restore();
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Problem is, the colors ain't right:
canvas.DrawColor() draws some shade of gray instead of Amber, although the holes appear to be ok.
Removing the saveLayer()/restore() calls draws the background with the right color, but then the holes ain't transparent.
Question now is: After filling the canvas with a color, how can you set parts of it to translucent?
If there's a more efficient/performant way to do it, please let me now as well - getting rid of the saveLayer() call would be great...
Any advise is welcome.
Thank you.
Try my version:
class Highlighter extends CustomPainter {
ValueListenable<double> valueListenable;
Color backgroundColor;
Rect target;
Highlighter({this.valueListenable, this.backgroundColor = Colors.amber, this.target = const Rect.fromLTWH(145, 320, 100, 100)})
: super(repaint: valueListenable);
#override
void paint(Canvas canvas, Size size) {
bool withRestore = false;
if (withRestore) {
//with canvas.restore
canvas.saveLayer(Rect.largest, Paint());
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), Paint()..color = backgroundColor.withOpacity(0.4));
canvas.drawRect(target, Paint()..blendMode = BlendMode.clear);
canvas.restore();
} else {
//without canvas.restore
Paint backgroundPaint = Paint();
backgroundPaint.blendMode = BlendMode.src;
backgroundPaint.color = backgroundColor.withOpacity(0.4);
// // Step 1: Draw the background:
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, target.top), backgroundPaint);
canvas.drawRect(Rect.fromLTWH(0, 0, target.left, size.height), backgroundPaint);
canvas.drawRect(Rect.fromLTWH(target.left + target.width, 0, target.left, size.height), backgroundPaint);
canvas.drawRect(Rect.fromLTWH(0, target.top + target.height, size.width, target.top), backgroundPaint);
}
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
The difficulty was to fade in/out the holes from the background (yellow) barrier. The approaches mentioned by #cloudpham93 and #YeasinSheikh do work, as long as you just want to cut a hole into the barrier.
If the holes should fade in/out however, the following steps are needed:
Call setLayer() and pass a Paint() with blendMode set to srcOver.
Draw the background barrier with the desired opacity.
Call setLayer() again, but pass a Paint() with blendMode set to dstOut.
Draw draw the holes with the desired opacity.
Call restore() twice. The first call of restore() will overwrite the opacity of the pixels on the background layer. The second call will draw the background layer onto whatever is underneath it.
Thanks for all the advise!

how can I make animation in flutter when filling specific (path)?

I want to make like this animation in flutter using canvas and paths
example of animation
You need to clip the canvas in your CustomPainter according to the value of the animation you are using. Code is below. It's hard to answer without seeing your code, but here is a skeleton of how to do it using CustomPaint. The canvas in CustomPaint can be clipped to a shape and the progress of the animation can be passed in.
Your CustomPaint would look like this:
CustomPaint(
painter: MyPainter(progress: animation.progress,..
And your CustomPainter would look something like this:
class MyPainter extends CustomPainter {
final double progress;
MyPainter({required this.progress...
#override
void paint(Canvas canvas, Size size) {
canvas.save();
double radius = min(size.width, size.height)/2*progress;
Offset center = size.center(Offset.zero);
Rect rect = Rect.fromCircle(center, radius);
RRect shape = RRect.fromRectAndRadius(rect, radius);
canvas.clipRRect(shape);
//your painting code here
canvas.restore();
}
This should clip your painting code to the circular shape.

How to draw custom shape in flutter and drag that shape around?

At the moment I can draw rectangles using CustomPainter. Below the code inside the paint method of my CustomPainter.
for (var rectPoints in rectangles) {
paint.color = rectPoints.color;
paint.strokeWidth = rectPoints.strokeWidth;
if (rectPoints.selected != null && rectPoints.selected == true) {
paint.color = Colors.black45;
}
var rect = Rect.fromLTWH(
rectPoints.startPoint.dx,
rectPoints.startPoint.dy,
rectPoints.endPoint.dx - rectPoints.startPoint.dx,
rectPoints.endPoint.dy - rectPoints.startPoint.dy);
canvas.drawRect(rect, paint);
}
var rect = Rect.fromLTWH(startPoint.dx, startPoint.dy,
endPoint.dx - startPoint.dx, endPoint.dy - startPoint.dy);
canvas.drawRect(rect, paint);
A rectangle is a custom object with startPoint, endPoint and some other properties needed to draw that specific rectangle. Now I want to select a rectangle and re-position it. Any help would be appreciated. Thanks
You'll need to track the state of the rectangles' positions independent of the canvas drawing. The easiest way to do that is to use a StatefulWidget. You'll also need to use a GestureDetector to capture the pan events. Then you can wire up the gesture details to the position of the rectangles and call the painter to redraw everything.
Here's a simple app that shows how to do it with one rectangle. Should be straightforward to expand it to handle multiple ones.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Draggable Custom Painter',
home: Scaffold(
body: CustomPainterDraggable(),
),
);
}
}
class CustomPainterDraggable extends StatefulWidget {
#override
_CustomPainterDraggableState createState() => _CustomPainterDraggableState();
}
class _CustomPainterDraggableState extends State<CustomPainterDraggable> {
var xPos = 0.0;
var yPos = 0.0;
final width = 100.0;
final height = 100.0;
bool _dragging = false;
/// Is the point (x, y) inside the rect?
bool _insideRect(double x, double y) =>
x >= xPos && x <= xPos + width && y >= yPos && y <= yPos + height;
#override
Widget build(BuildContext context) {
return GestureDetector(
onPanStart: (details) => _dragging = _insideRect(
details.globalPosition.dx,
details.globalPosition.dy,
),
onPanEnd: (details) {
_dragging = false;
},
onPanUpdate: (details) {
if (_dragging) {
setState(() {
xPos += details.delta.dx;
yPos += details.delta.dy;
});
}
},
child: Container(
color: Colors.white,
child: CustomPaint(
painter: RectanglePainter(Rect.fromLTWH(xPos, yPos, width, height)),
child: Container(),
),
),
);
}
}
class RectanglePainter extends CustomPainter {
RectanglePainter(this.rect);
final Rect rect;
#override
void paint(Canvas canvas, Size size) {
canvas.drawRect(rect, Paint());
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
I have developed a library called
touchable for the purpose of adding gesture callbacks to each individual shape you draw on the canvas. You can draw your shapes and add onPanUpdate or onTapDown callbacks to drag your shape around.
Here's what you can do to detect touch and drag on your circle.
Here's a small example taken directly from the pub dev site :
Wrap your CustomPaint widget with CanvasTouchDetector. It takes a builder function as argument that expects your CustomPaint widget as shown below.
import 'package:touchable/touchable.dart';
CanvasTouchDetector(
builder: (context) =>
CustomPaint(
painter: MyPainter(context)
)
)
Inside your CustomPainter class's paint method , create and use the TouchyCanvas object (using the context obtained from the CanvasTouchDetector and canvas) to draw your shape and you can give gesture callbacks like onPanUpdate , onTapDown here to detect your drag events.
var myCanvas = TouchyCanvas(context,canvas);
myCanvas.drawRect( rect , Paint() , onPanUpdate: (detail){
//This callback runs when you drag this rectangle. Details of the location can be got from the detail object.
//Do stuff here. Probably change your state and animate
});