Rounding the drawn line(path) with flutter custom painter - flutter

I have below custom painter and I want to round any edge of the path
I will be grateful if you help

you can use this CustomPainter:
class CustomDraw extends CustomPainter {
late Paint painter;
late double radius;
CustomDraw(Color color, {this.radius = 0}) {
painter = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 10
..strokeCap = StrokeCap.round
..color = color;
}
#override
void paint(Canvas canvas, Size size) {
var path = Path();
path.moveTo(size.width, 0);
path.lineTo(0 + radius, 0);
path.cubicTo(0 + radius, 0, 0, 0, 0, radius);
path.lineTo(0, 35 - radius);
path.cubicTo(0, 35 - radius, 0, 35, radius, 35);
path.lineTo(size.width - radius, 35);
path.cubicTo(
size.width - radius, 35, size.width, 35, size.width, 35 + radius);
path.lineTo(size.width, 35 + 35 - radius);
path.cubicTo(size.width, 35 + 35 - radius, size.width, 35 + 35,
size.width - radius, 35 + 35);
path.lineTo(0, 35 + 35);
canvas.drawPath(path, painter);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
use it like this:
CustomPaint(
painter: CustomDraw(Colors.red, radius: 16),
child: SizedBox(
height: 100,
width: 200,
),
),

Related

How to draw an Arc in the middle of CustomPainter shape

I am trying to draw the following shape using CustomPainter, I am looking for a way
to make this shape as one shape (union), so for example using Stack with Container and half circle shape is not desired.
I have managed to paint the base rectangular shape as the following image shows, is it possible to build on top of this code to draw a half a circle in the middle ?
Container(
height: 85,
color: Colors.blueGrey,
child: Stack(
children: [
CustomPaint(
size: Size(size.width, 85),
painter: MyCustomPainter(),
)
],
),
),
class MyCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
var paint = Paint()
..color = Colors.red
..style = PaintingStyle.fill;
var path = Path()..moveTo(0, 20);
path.quadraticBezierTo(0, 0, 0, size.height * 0.5);
path.quadraticBezierTo(0, 0, size.width * 0.2, 0);
path.quadraticBezierTo(size.width, 0, size.width * 0.8, 0);
path.quadraticBezierTo(size.width, 0, size.width, size.height * 0.5);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
While the question about using union operation, I am focusing on
canvas.drawPath(
Path.combine(PathOperation.union, path1, circlePath), paint);
The current paint takes full height and doesnt maintain the ration based on your desire result. I am using Rect on Path to demonstrating the union operation. Change the size/value according to your needs.
class MyCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
var paint = Paint()
..color = Colors.red
..style = PaintingStyle.fill;
final double base = size.height * .4;
const corner = Radius.circular(16);
final path1 = Path()
..addRRect(
RRect.fromLTRBAndCorners(0, base, size.width, size.height,
topLeft: corner, topRight: corner),
);
final center = Offset(size.width / 2, size.height / 2);
final radius = size.height / 2;
final circlePath = Path()
..addOval(Rect.fromCircle(center: center, radius: radius));
canvas.drawPath(
Path.combine(PathOperation.union, path1, circlePath), paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
More about CustomPaint

Flutter reverse clipper direction

I need to show triangle type shape container which is almost complete but there is one issue its showing the triangle shape in opposite direction my code
class ClipPathClass extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var roundnessFactor = 50.0;
var path = Path();
path.moveTo(0, size.height * 0.33);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(
size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, roundnessFactor * 2);
path.quadraticBezierTo(size.width - 10, roundnessFactor,
size.width - roundnessFactor * 1.5, roundnessFactor * 1.5);
path.lineTo(
roundnessFactor * 0.6, size.height * 0.33 - roundnessFactor * 0.3);
path.quadraticBezierTo(
0, size.height * 0.33, 0, size.height * 0.33 + roundnessFactor);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
This is how i am showing this
ClipPath(
clipper: RoundedDiagonalPathClipper(),
child: Container(
height: 320,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.0)),
color: Colors.orange,
),
child: null,
),
),
Out put is showing like this
But i need to show the upper part like this just reverse it. I play with everything but it's not reversing.
I implemented _getY function so that there is no bend in the corner. And I added an equalization variable to make look better.
Reference: Paths in Flutter: A Visual Guide.
Screenshot
RoundedDiagonalPathClipper.dart
class RoundedDiagonalPathClipper extends CustomClipper<Path> {
double _getY(double x) {
return x * 0.33;
}
#override
Path getClip(Size size) {
var roundnessFactor = 50.0;
var equalization = 10.0;
var path = Path();
path.moveTo(0, roundnessFactor);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(
size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, _getY(size.width) + roundnessFactor - equalization);
path.quadraticBezierTo(
size.width,
_getY(size.width),
size.width - roundnessFactor + equalization,
_getY(size.width - roundnessFactor + equalization));
path.lineTo(
roundnessFactor + equalization, _getY(roundnessFactor + equalization));
path.quadraticBezierTo(0, 0, 0, roundnessFactor + equalization);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
Edit: Adding shadow
I made the shadow version by using the gist:coman3-ClipShadowPath.dart.
ClipShadowPath.dart
#immutable
class ClipShadowPath extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Path> clipper;
final Widget child;
ClipShadowPath({
required this.shadow,
required this.clipper,
required this.child,
});
#override
Widget build(BuildContext context) {
return CustomPaint(
key: UniqueKey(),
painter: _ClipShadowShadowPainter(
clipper: this.clipper,
shadow: this.shadow,
),
child: ClipPath(child: child, clipper: this.clipper),
);
}
}
class _ClipShadowShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Path> clipper;
_ClipShadowShadowPainter({required this.shadow, required this.clipper});
#override
void paint(Canvas canvas, Size size) {
var paint = shadow.toPaint();
var clipPath = clipper.getClip(size).shift(shadow.offset);
canvas.drawPath(clipPath, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Usage
ClipShadowPath(
shadow: Shadow(blurRadius: 20.0, color: Colors.black54),
clipper: RoundedDiagonalPathClipper(),
child: Container(color: Colors.orange),
)
just apply Matrix transformation on Path, so you will free to do any changes on path, it will flip vertically any path
how to use:
clipper: ClipPathClass(),
or if need to reverse
clipper: ClipPathClass(flip: true),
class ClipPathClass extends CustomClipper<Path> {
final roundnessFactor = 50.0;
final bool flip;
ClipPathClass({this.flip = false});
#override
Path getClip(Size size) {
final path = Path();
path.moveTo(0, size.height * 0.33);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, roundnessFactor * 2);
path.quadraticBezierTo(size.width - 10, roundnessFactor, size.width - roundnessFactor * 1.5, roundnessFactor * 1.5);
path.lineTo(roundnessFactor * 0.6, size.height * 0.33 - roundnessFactor * 0.3);
path.quadraticBezierTo(0, size.height * 0.33, 0, size.height * 0.33 + roundnessFactor);
return flip ? _flip(path, size.width) : path;
}
Path _flip(Path path, double width) {
final m = Matrix4.identity()
..translate(width)
..rotateY(math.pi);
return path.transform(m.storage);
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
I won't explain the change line by line, I tried to keep the round corner uniform on the four corners.
Here your are:
class RoundedDiagonalPathClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var roundnessFactor = 50.0;
var path = Path();
path.moveTo(0, roundnessFactor);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(
size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, size.height * 0.33 + roundnessFactor * 0.5);
path.quadraticBezierTo(
size.width,
size.height * 0.33,
size.width - roundnessFactor,
size.height * 0.33 - roundnessFactor * 0.5);
path.lineTo(roundnessFactor, 0);
path.quadraticBezierTo(0, 0, 0, roundnessFactor);
return path;
}
The result will be this one:

Flutter Drawing a Skewed Oval Using CustomPainter

I'm trying to draw this oval in Custom Painter.
I can't seem to wrap my head around it. I've tried using the drawOval() function on the Canvas:
#override
void paint(Canvas canvas, Size size) {
final startAngle = -math.pi / 2;
final sweepAngle = math.pi;
Offset center = Offset(size.width * 0.5, size.height * 0.5);
int lineAmount = 10;
Color paintColor = Color.fromRGBO(250, 154, 210, 1);
Paint circlePaint = Paint()
..color = paintColor
..style = PaintingStyle.stroke
..strokeWidth = 5;
// HIGHLIGHT
canvas.drawOval(Rect.fromLTRB(50, 100, 250, 200), circlePaint);
}
... and using the drawArc() function:
canvas.drawArc(Rect.fromLTRB(50, 100, 250, 200), startAngle, sweepAngle,
false, circlePaint);
canvas.drawArc(Rect.fromLTRB(50, 100, 250, 200), -startAngle, -sweepAngle,
false, circlePaint);
This is the result I keep on getting:
How can I properly draw the arc?
as an option you can use canvas transformations - translate and rotate
like this:
#override
void paint(Canvas canvas, Size size) {
final angle = -math.pi / 4;
Color paintColor = Color.fromRGBO(250, 154, 210, 1);
Paint circlePaint = Paint()
..color = paintColor
..style = PaintingStyle.stroke
..strokeWidth = 5;
canvas.save();
canvas.translate(size.width * 0.5, size.height * 0.5);
canvas.rotate(angle);
canvas.drawOval(Rect.fromCenter(center: Offset.zero, width: 50, height: 100), circlePaint);
canvas.restore();
}

Fllutter - How to create a custom shape

the bellow image that is what i want to draw it using CustomPainter with LinearGradient and have shadow
already i draw bellow circle shape but not same and have LinearGradient
class CurvePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Rect rect = new Rect.fromCircle(
center: new Offset(165.0, 55.0),
radius: 180.0,
);
final Gradient gradient = new LinearGradient(
colors: <Color>[
const Color(0xFF2151a6),
const Color(0xFF3377f4),
],
);
var paint = Paint()..shader = gradient.createShader(rect);
paint.color = Colors.green[800];
paint.style = PaintingStyle.fill; // Change this to fill
var path = Path();
path.moveTo(0, size.height * 0.35);
path.moveTo(0, size.height * 0.3);
path.quadraticBezierTo(
size.width / 2, size.height / 2.4, size.width, size.height * 0.35);
path.lineTo(size.width, 0);
path.lineTo(0, 0);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
I think I drew it well
try this:
class CurvePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Rect rect = new Rect.fromCircle(
center: new Offset(165.0, 55.0),
radius: 180.0,
);
final Gradient gradient = new LinearGradient(
colors: <Color>[
const Color(0xFF2151a6),
const Color(0xFF3377f4),
],
);
var paint = Paint()..shader = gradient.createShader(rect);
paint.color = Colors.green[800];
paint.style = PaintingStyle.fill; // Change this to fill
var path = Path();
path.moveTo(0, size.height * 0.32);
path.lineTo(size.width * 0.20, size.height * 0.34);
path.quadraticBezierTo( size.width * 0.30, size.height * 0.35,
size.width * 0.40, size.height * 0.34 );
path.lineTo(size.width*0.9, size.height * 0.26);
path.quadraticBezierTo( size.width, size.height * 0.24,
size.width , size.height * 0.20);
path.lineTo(size.width, 0);
path.lineTo(0 , 0);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}

How to fill color inside a shape created using CustomPainter drawPath?

So, I've created a shape using drawPath and drawArc from CustomPainter, the PaintingStyle is stroke, but when I change it to fill, it only fills the arcs and not the whole shape.
I want to fill the shape I created with a color, so how can I fill the shape with a particular color?
class CustomShapeCard extends CustomPainter {
CustomShapeCard({#required this.strokeWidth, #required this.color});
final double strokeWidth;
final Color color;
#override
void paint(Canvas canvas, Size size) {
var paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth
..color = color;
var path = Path();
path.moveTo(size.width * 0.1, size.height * 0.2);
path.lineTo(size.width * 0.1, size.height * 0.9);
canvas.drawPath(path, paint);
canvas.drawArc(
Rect.fromCenter(
center: Offset((size.width * 0.2) - 14, size.height * 0.9),
height: 50,
width: 50,
),
math.pi / 2,
math.pi / 2,
false,
paint,
);
path.moveTo((size.width * 0.2) - 14, (size.height * 0.9) + 25);
path.lineTo((size.width * 0.9) - 25, size.height * 0.9 + 25);
canvas.drawPath(path, paint);
canvas.drawArc(
Rect.fromCenter(
center: Offset((size.width * 0.9) - 25, size.height * 0.9),
height: 50,
width: 50,
),
math.pi / 2,
-math.pi / 2,
false,
paint,
);
path.moveTo((size.width * 0.9), (size.height * 0.9));
path.lineTo(size.width * 0.9, size.height * 0.35);
canvas.drawPath(path, paint);
canvas.drawArc(
Rect.fromCenter(
center: Offset((size.width * 0.9) - 25, size.height * 0.35),
height: 50,
width: 50,
),
-math.pi / 2,
math.pi / 2,
false,
paint,
);
path.moveTo((size.width * 0.9) - 25, (size.height * 0.35) - 25);
path.lineTo(size.width * 0.25, (size.height * 0.35) - 25);
canvas.drawPath(path, paint);
canvas.drawArc(
Rect.fromCenter(
center: Offset((size.width * 0.25), (size.height * 0.35) - 50),
height: 50,
width: 50,
),
math.pi / 2,
math.pi / 3,
false,
paint,
);
path.moveTo((size.width * 0.25) - 20, (size.height * 0.35) - 35);
path.lineTo(size.width * 0.1, size.height * 0.2);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
When the PaintingStyle is stroke, I get this,
When I change PaintingStyle to fill, I get,
To fill a shape like this with a color,
the arcToPoint() should be used instead of drawArc().