How to Insert/draw Image/text inside canvas circle in flutter - flutter

I want to draw/insert image and text inside canvas circle but I am unable to do that. I am posting screenshot for better understanding of my requirements
Image
Code
void paint(Canvas canvas, Size size) {
Size size = MediaQuery.of(buildContext).size;
double strokeWidth = 10;
Rect myRect = Offset(-size.width * 0.21, -40) &
Size(size.width * 0.195, size.width * 0.195);
var paint1 = Paint()
..color = Color(0xFF23BBFF)
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
var paint2 = Paint()
..color = Color(0xFFFF8623)
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
double firstLineRadianStart = 0;
double _unAnswered = 0.30;
double firstLineRadianEnd = (360 * _unAnswered) * pi / 180;
canvas.drawArc(
myRect, firstLineRadianStart, firstLineRadianEnd, false, paint1);
double _learned = 1 - _unAnswered;
double secondLineRadianEnd = getRadians(_learned);
canvas.drawArc(
myRect, firstLineRadianEnd, secondLineRadianEnd, false, paint2);
}
double getRadians(double value) {
return (360 * value) * pi / 180;
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;

Related

Flutter - how do I rotate an object on a CustomPainter canvas?

How do you rotate an object drawn on a canvas in Flutter (not the whole canvas, just the object)?
The following does not work. Error is: This expression has a type of 'void' so its value can't be used.
Transform.rotate(
angle: pi,
child: canvas.drawPath(
getTrianglePath(Offset(secondhandX, secondhandY)),
secondhandBrush));
Here is the full code:
// imports omitted
class TimerDialPainter extends CustomPainter {
Path getTrianglePath(Offset position) {
return Path()
..moveTo(position.dx - 20, position.dy - 20)
..lineTo(position.dx + 40, position.dy + 40)
..lineTo(position.dx - 20, position.dy + 40)
..lineTo(position.dx - 20, position.dy - 20);
}
#override
void paint(Canvas canvas, Size size) {
int centerX = size.width / 2;
int centerY = size.height / 2;
int secondsArc = 60;
Paint countBrush = Paint()
..color = (Colors.red)
..style = PaintingStyle.fill
..strokeWidth = 3;
var secondhandX = centerX + 80 * cos(secondsArc * pi / 180);
var secondhandY = centerY + 80 * sin(secondsArc * pi / 180);
Transform.rotate(
angle: pi/3,
child: canvas.drawPath(
getTrianglePath(Offset(secondhandX, secondhandY)),
countBrush));
} //I feel this is not a right place to solve this??
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
Try rotating the canvas and paint it. Then rotate it back to previous value
#override
void paint(Canvas canvas, Size size) {
double centerX = size.width / 2;
double centerY = size.height / 2;
int secondsArc = 60;
Paint countBrush = Paint()
..color = (Colors.red)
..style = PaintingStyle.fill
..strokeWidth = 3;
num secondhandX = centerX + 80 * cos(secondsArc * pi / 180);
num secondhandY = centerY + 80 * sin(secondsArc * pi / 180);
canvas.rotate(40);
canvas.drawPath(
getTrianglePath(Offset(secondhandX.toDouble(), secondhandY.toDouble())),
countBrush);
canvas.rotate(0);
}

How to a create a pet paw logo using canvas in flutter

I am trying to create a paw pet canvas as the below logo dynamically using flutter:
as I tried to create a using Paint() Canvas as the below code:
class PetLogo extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
Paint paint = Paint();
paint
..color = Colors.white
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round
..strokeWidth = 3;
Paint paint1 = Paint();
paint1
..color = Colors.transparent
..style = PaintingStyle.fill
..strokeWidth = 0;
var paint2 = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round
..strokeWidth = 3;
//a circle
canvas.drawCircle(Offset(0, 9), 18, paint2);
var paint3 = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round
..strokeWidth = 3;
//a circle
canvas.drawCircle(Offset(50, 0), 22, paint3);
var paint4 = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round
..strokeWidth = 3;
//a circle
canvas.drawCircle(Offset(100, 10), 18, paint4);
double width = size.width;
double height = size.height;
Path path = Path();
path.moveTo(0.5 * width, height * 0.45);
path.cubicTo(0.2 * width, height * 0.1, -0.50 * width, height * 0.6,
0.5 * width, height);
path.moveTo(0.5 * width, height * 0.45);
path.cubicTo(0.8 * width, height * 0.1, 1.50 * width, height * 0.6,
0.5 * width, height);
canvas.drawPath(path, paint1);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
as the final output looks like the below figure:
So there's any one could help me to complete this paint?

How Can I Create Arc with Radius CustomPainter like this Mockup

Please tell me how can I create this Arc with Radius CustomPainter UI Component like this Mockup Design?
There must be a gap between Start & End angle.
Code:
class ArcPainter extends CustomPainter {
final double angle = 310.0;
double toAngle(double angle) => angle * pi / 180.0;
#override
void paint(Canvas canvas, Size size) {
final Offset center = Offset(size.width / 2.0, size.height / 2.0);
final double radius = size.width / 3.0;
Paint paint = Paint()
..strokeCap = StrokeCap.round
..strokeWidth = 8.0
..style = PaintingStyle.stroke
..color = Colors.pink;
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius),
toAngle(110.0),
toAngle(angle),
true,
paint,
);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Problem:
Here is the current output for my Arc with Radius. The problem is that borders are showing in the arc gap. I want to remove the border in the gap.
you can create drawPath instead of drawArc
#override
void paint(Canvas canvas, Size size) {
final center = size.center(Offset.zero);
final oval = Rect.fromCenter(
center: center,
width: size.width,
height: size.height,
);
var progressPath = _path(oval, 200);
var progressPaint = _paint(Color(0xFF8987F7));
var backgroundPath = _path(oval, 280);
var backgroundPaint = _paint(Color(0xFF3a329e));
canvas
..drawPath(backgroundPath, backgroundPaint)
..drawPath(progressPath, progressPaint);
}
Paint _paint(Color color) {
return Paint()
..strokeCap = StrokeCap.round
..strokeWidth = 15.0
..style = PaintingStyle.stroke
..color = color;
}
Path _path(Rect oval, double angle) {
return Path()
..addArc(
oval,
toAngle(130),
toAngle(angle),
);
}
You told it to close the gap using the center. You can tell it to not do so:
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius),
toAngle(110.0),
toAngle(angle),
false, // this is called "useCenter" for a reason...
paint,
);

How to include Stroke Cap in Sweep Gradient?

You can see my arc starts from top but there is some area which is painted pink, it should be white. I think it is because I am using StrokeCap.round, but how do I remove that part?
Painter class:
class MyPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
double centerPoint = size.height / 2;
Paint paint = Paint()
..color = Colors.white
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 20;
paint.shader = SweepGradient(
colors: [Colors.white, Colors.pink],
tileMode: TileMode.repeated,
startAngle: _degreeToRad(270),
endAngle: _degreeToRad(270 + 360.0),
).createShader(Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: 0));
double startAngle = _degreeToRad(270);
double sweepAngle = _degreeToRad(95 / 100 * 360);
Rect rect = Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: centerPoint);
canvas.drawArc(rect, startAngle, sweepAngle, false, paint);
}
double _degreeToRad(double degree) => degree * math.pi / 180;
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Usage:
CustomPaint(
size: Size.fromRadius(100),
painter: MyPainter(),
)
when you are using strokeCap = StrokeCap.round it adds half of the stroke width to start of your line and half of it to the end for creating the round edges of the line so in your calculation you should remove half of the stroke Width from the start and a half of it from end
I changed your code and it works as should here is the code:
class MyPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
double centerPoint = size.height / 2;
double strokeWidth = 30;
double percentValue=100/100;
double radius=centerPoint;
Paint paint = Paint()
..color = Colors.white
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth;
paint.shader = SweepGradient(
colors: [Colors.black, Colors.pink],
tileMode: TileMode.repeated,
startAngle: _degreeToRad(270),
endAngle: _degreeToRad(270 + 360.0),
).createShader(Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: 0));
Rect rect = Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: radius);
var scapSize = strokeWidth / 2;
double scapToDegree = scapSize / radius;
double startAngle = _degreeToRad(270)+scapToDegree;
double sweepAngle = _degreeToRad( 360)-(2*scapToDegree);
canvas.drawArc(rect, startAngle, percentValue*sweepAngle, false, paint);
}
double _degreeToRad(double degree) => degree * pi / 180;
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
And a performance tip for you :
don't create your shader and gradient each time , the Paint method
will be executed numers of time so you should check if you already
created the shader for the inComing size use that and don't create it
again

Can't recreate this floating widget

I'm currently blocked trying to create a widget (like a tooltip box) that is represented by the image below. I should probably be able to create it by relying on a Painter class, but i'm not familiar doing so...
https://pasteboard.co/IgccNxD.png
(it's small, yes, max height = ~35px)
The code ended being something like:
void paint(Canvas canvas, Size size) {
Paint p = Paint()
..color = Colors.red
..isAntiAlias = true
..style = PaintingStyle.fill;
Offset nw = Offset(0, 0);
Offset se = Offset(size.width, size.height * 0.8);
final Rect rect = Rect.fromPoints(nw, se);
final RRect r = RRect.fromRectAndRadius(rect, Radius.circular(10));
canvas.drawRRect(r, p);
Offset bottomPoint = Offset((size.width / 2), size.height);
Offset rightPoint = Offset((size.width / 2) * 0.80, size.height * 0.80);
Offset leftPoint = Offset((size.width / 2) * 1.20, size.height * 0.80);
var path1 = Path()
..moveTo(rightPoint.dx, rightPoint.dy)
..lineTo(bottomPoint.dx, bottomPoint.dy)
..lineTo(leftPoint.dx, leftPoint.dy)
..lineTo(rightPoint.dx, rightPoint.dy);
canvas.drawPath(path1, p);
}
For the text inside, I've stacked it above this painting.