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
)
Related
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
I want to design this appbar :
and my code in main.dart is :
#override
Widget build(BuildContext context) {
return Column(
children: [
ClipPath(
clipper: WaveClip(),
child: Container(
height: 200,
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF7CB342), Color(0xFFDCEDC8)],
),
),
child: childWidget),
),
],
);
and the WaveClip is:
class WaveClip extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = new Path();
path.lineTo(0, 0); //start path with this if you are making at bottom
path.lineTo(0, size.height); //start path with this if you are making at bottom
var controlpoint = Offset(size.width / 5 , size.height - 100);
var endpoint = Offset(size.width / 3 , size.height +50);
path.quadraticBezierTo(
controlpoint.dx, controlpoint.dy, endpoint.dx, endpoint.dy);
var controlpoint2 = Offset(size.width /2 , size.height +90 );
var endpoint2 = Offset(size.width /4 , size.height -50);
path.quadraticBezierTo(
controlpoint2.dx, controlpoint2.dy, endpoint2.dx, endpoint2.dy);
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0.0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
but i cant handle it and my code does not works true, how can I fix it?
Should i use path.cubicto to design it?
It's better to use custompainter instead of customclipper, and there is a website that automatically generates custompainter code base on your drawing
https://shapemaker.web.app
And this is the guide to use this auto shape maker:
https://youtu.be/AnKgtKxRLX4
I hope this help u to solve your problem
I wanted to create the curved container like widget in the picture below
I used the Custom clipper class and created a similar one which is shown below
Below is the WaveClipper class I used to create the curved widget
class WaveClipper extends CustomClipper<Path> {
#override
getClip(Size size) {
var path = new Path();
path.lineTo(0, size.height / 5.25);
var firstControlPoint = Offset(size.width / 120, size.height / 2);
var firstEndPoint = Offset(size.width / 1.5, size.height / 2.5 );
var thirdControlPoint = Offset(size.width/1.025, size.height / 2.8 );
var thirdEndPoint = Offset(size.width, size.height / 1.8 );
path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy, firstEndPoint.dx,
firstEndPoint.dy);
path.quadraticBezierTo(thirdControlPoint.dx, thirdControlPoint.dy, thirdEndPoint.dx,
thirdEndPoint.dy);
path.lineTo(size.width, size.height/3 );
path.lineTo(size.width, 0);
path.close();
return path;
}
#override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return true;
}
}
Please help me to achieve the desired output !!!
By wrapping the ClipPath widget with the container you can create your design see below code.
Container(
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.blue),
color: Colors.blue),
child: ClipPath(
child: Container(
height: 200,
width: 200,
color: Colors.white,
),
clipper: WaveClipper()),
),
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();
}
}
for my Container borderRadius. I am currently using borderRadius: BorderRadius.all(Radius.circular(20)). I want instead of it taking out the inside I want a border that adds to the outside like a triangluar like shape thing instead of taking away a triangleish looking thing.
you can do this easily using a custom ClipperPath.
Define a custom ClipperPath as given below.
class CustomClipPath extends CustomClipper<Path> {
final radius = 10.0;
final arcHeight = 50.0;
#override
Path getClip(Size size) {
final path = Path();
path.lineTo(size.width, 0.0);
path.lineTo(size.width, size.height);
path.arcToPoint(Offset(size.width, size.height - arcHeight),
radius: Radius.circular(radius));
path.lineTo(size.width, size.height - arcHeight / 2);
path.lineTo(0, size.height - arcHeight / 2);
path.lineTo(0,size.height- arcHeight);
path.arcToPoint(Offset(0, size.height),
radius: Radius.circular(radius));
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
Then you can apply it to any container like shown below.
ClipPath(
child: Container(
width: MediaQuery.of(context).size.width,
height: 200,
alignment:Alignment.center,
color: Colors.blue,
),
clipper: CustomClipPath(),
)
I am sharing a live demo on the Dartpad, find it here.