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
Related
I want a bottom border in the above given way for an image
I have used ClipRRect for the same
ClipRRect(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(50),
bottomRight: Radius.circular(50)),
// Image border
child: SizedBox.fromSize(
size: Size.fromRadius(48), // Image radius
child: Image.network(data['displayPic'],
fit: BoxFit.cover),
),
)),
You could create CustomClipper , I will share an example Code which will achieve the way you want to shape the image , you could change radius according to your need.
class ClipPathClass extends CustomClipper<Path> {
#override
Path getClip(Size size) {
double radius = 50;
var path = Path();
path.lineTo(0.0, size.height - 30);
var firstControlPoint = Offset(size.width / 4, size.height);
var firstPoint = Offset(size.width / 2, size.height);
path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
firstPoint.dx, firstPoint.dy);
var secondControlPoint = Offset(size.width - (size.width / 4), size.height);
var secondPoint = Offset(size.width, size.height - 30);
path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy,
secondPoint.dx, secondPoint.dy);
path.lineTo(size.width, 0.0);
path.lineTo(size.width - radius, 0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
Now use this ClipPathClass like ,
ClipPath(
clipper: ClipPathClass(),
child: //Your Image Container here
)
I made a custom shape of a crooked square for music artwork images, now I'm trying to make the image fill it completely whilst not leaking out of it.
I tried using a stack, but it is bugging the painted square and the image still would leak and not fill it completely.
SizedBox(
width: 50,
height: 50,
child: CustomPaint(
painter: ImperfectRectangleBorder(strokeColor: Colors.white),
child: QueryArtworkWidget(//from on_audio_query package
artworkBorder: BorderRadius.zero,
artworkFit: BoxFit.fill,
id: item.data![index].id,
type: ArtworkType.AUDIO,
),
),
),
class ImperfectRectangleBorder extends CustomPainter {
final Color strokeColor;
ImperfectRectangleBorder({this.strokeColor = Colors.white});
#override
void paint(Canvas canvas, Size size) {
var paint = Paint()
..color = strokeColor
..strokeWidth = 4.0
..style = PaintingStyle.stroke;
var path = Path();
path.moveTo(0, -5);
path.lineTo(size.width * (0.2), size.height + 10);
path.lineTo(size.width, size.height - 5);
path.lineTo(size.height * (0.8), -1);
path.close();
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
Idea is to make a custom shaped container by giving it ShapeDecoration().
I used this thread as a reference.
Eventialy I achieved the shape I wanted, but once I wrap this custom shaped container with margin\padding\SizedBoxes around it - it's content is being pushed out of the bounds of the container. Check out screenshots.
Normaly it should be smth like this:
but with paddings between elements.
So the problem is that my customized container behavers realy wierd once it has any margin\padding arround it.
return Padding(
padding: const EdgeInsets.symmetric(vertical: 40),
child: Container(
padding: const EdgeInsets.all(8),
height: 88,
alignment: Alignment.center,
decoration: ShapeDecoration(
shape: UnitListItemBorderShape(
color: _isCurrent ? theme.listItemBorderColor : theme.listItemBackgroundColor,
),
color: theme.listItemBackgroundColor,
),
child: Stack(
children: [
//custom container's ineer content
] ,
),
);
UnitListItemBorderShape class:
class UnitListItemBorderShape extends ShapeBorder {
const UnitListItemBorderShape({color}) : _color = color;
final Color _color;
#override
EdgeInsetsGeometry get dimensions => const EdgeInsets.all(0);
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) => UnitListItemShape.getShape(
rect.width,
rect.height,
const Radius.circular(16),
const Radius.circular(20),
);
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
final Paint borderPaint = Paint()
..color = _color
..style = PaintingStyle.stroke
..strokeWidth = 2;
canvas.drawPath(getOuterPath(rect), borderPaint);
}
#override
ShapeBorder scale(double t) => null;
}
UnitListItemShape class:
class UnitListItemShape {
static Path getShape(double width, double height, Radius borderRadius, Radius circleRadius) {
final double rightOffset = circleRadius.x;
final Rect rect = Rect.fromCenter(center: Offset(width - rightOffset - 4, height / 2), width: 48, height: 48);
return Path()
..moveTo(borderRadius.x, 0)
..lineTo(width - borderRadius.x - rightOffset, 0)
..arcToPoint(Offset(width - rightOffset, borderRadius.x), radius: borderRadius)
..lineTo(width - rightOffset, (height / 2) - rightOffset - 4)
// ..addRect(rect)
..arcTo(rect, -70 * math.pi / 180, 150 * math.pi / 180, false)
..lineTo(width - rightOffset, height - borderRadius.x)
..arcToPoint(Offset(width - borderRadius.x - rightOffset, height), radius: borderRadius)
..lineTo(borderRadius.x, height)
..arcToPoint(Offset(0, height - borderRadius.x), radius: borderRadius)
..lineTo(0, borderRadius.x)
..arcToPoint(Offset(borderRadius.x, 0), radius: borderRadius)
..fillType = PathFillType.evenOdd
..close();
}
}
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();
}
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;
}
}