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:
Related
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;}
}
i am trying to create chart like this that has a circular border
i want to create custom like this/
how i am gonna do that , is there any packages that i can modify it and make it like this
If you want to create a chart, you can use syncfusion_flutter_charts
and if you want create curves you can use CustomPaint widget. one example I find in my code for you:
CustomPaint(
painter: CurveBackground(color: \\ yourColor),
child: \\ your child
)
class CurveBackground extends CustomPainter {
final Color color;
CurveBackground({this.color});
#override
void paint(Canvas canvas, Size size) {
var paint = Paint();
paint.color = color;
paint.style = PaintingStyle.fill;
var path = Path();
path.moveTo(0, Dimens.size_30());
path.quadraticBezierTo(size.width * 0.4, size.height * 0.1,
size.width * 0.3, size.height * 0.3);
path.quadraticBezierTo(size.width * 0.1, size.height * 0.6,
size.width * 0.45, size.height * 0.7);
path.quadraticBezierTo(
size.width * 1, size.height * 0.9, size.width * 0.9, size.height * 1.0);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
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;
}
}
I am trying to draw the picture below using the flutter customPainter library. How can I draw this shape?
My codes and the result
import 'package:flutter/material.dart';
class CurvePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
var paint = new Paint();
paint.color = Colors.green[800];
paint.style = PaintingStyle.fill;
var path = new Path();
path.lineTo(0, size.height * 0.3);
path.quadraticBezierTo(size.width * 0.35, size.height * 0.4, size.width * 0.7, size.height * 0.21);
path.quadraticBezierTo(size.width * 0.6, size.height * 0.19, size.width * 0.9, size.height * 0.15);
path.quadraticBezierTo(size.width , size.height * 0.05, size.width * 0.6, 0);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
The Bézier curves you chose are not the correct ones.
Here I illustrate where I applied which curves. The yellow dots are start & end points and the black dots represent control points.
In the code, I went from left to right (top to bottom) and used arcToPoint instead of conicTo as it works better. Note that arcToPoint draws conic curves as well.
It is just a rough sketch, i.e. the proportions are completely off, but at least I can share the proper Bézier curves you should use in order to achieve your desired output.
#override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.red[800]
..style = PaintingStyle.fill;
final path = new Path()
..moveTo(size.width * .6, 0)
..quadraticBezierTo(
size.width * .7,
size.height * .08,
size.width * .9,
size.height * .05,
)
..arcToPoint(
Offset(
size.width * .93,
size.height * .15,
),
radius: Radius.circular(size.height * .05),
largeArc: true,
)
..cubicTo(
size.width * .6,
size.height * .15,
size.width * .5,
size.height * .46,
0,
size.height * .3,
)
..lineTo(0, 0)
..close();
canvas.drawPath(path, paint);
}
Note that I updated the syntax to use .. cascade notation and the final keyword for the variables.
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;
}