I would like ideas for how to implement a custom border as shown in the image below.
I made a CustomPainter to draw the shape:
class MyPainter extends CustomPainter {
Color color;
MyPainter({#required this.color});
#override
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = color
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 2;
var path = Path();
final double startPoint = size.width * 0.2;
final double rheight = 30;
path.moveTo(startPoint, rheight);
path.lineTo(startPoint + 20, 0);
path.lineTo(startPoint + 40, rheight);
path.moveTo(0, rheight);
path.lineTo(startPoint, rheight);
path.moveTo(startPoint + 40, rheight);
path.lineTo(size.width, rheight);
path.lineTo(size.width, size.height);
path.moveTo(0, rheight);
path.lineTo(0, size.height);
path.moveTo(0, size.height);
path.lineTo(size.width, size.height);
path.close();
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Usage:
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Padding(
padding: const EdgeInsets.all(30.0),
child: CustomPaint(
painter: MyPainter(color: Colors.black.withOpacity(0.2)),
child: Container(
height: 300,
)
),
),
),
);
}
Result:
Update: This is a curved edges version:
class MyPainter extends CustomPainter {
Color color;
MyPainter({#required this.color});
#override
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = color
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 2;
var path = Path();
final double startPoint = size.width * 0.2;
final double rheight = 30;
path.moveTo(startPoint, rheight);
path.lineTo(startPoint + 20, 5);
path.cubicTo(startPoint + 23, 0, startPoint + 26, 0,
startPoint + 29, 0);
path.lineTo(startPoint + 50, rheight);
path.moveTo(10, rheight);
path.lineTo(startPoint, rheight);
path.moveTo(startPoint + 50, rheight);
path.lineTo(size.width - 10, rheight);
path.cubicTo(size.width, rheight + 5, size.width, rheight + 10,
size.width, rheight + 15);
path.lineTo(size.width, size.height - 15);
path.moveTo(10, rheight);
path.cubicTo(0, rheight + 5, 0, rheight + 10,
0, rheight + 15);
path.lineTo(0, size.height - 10);
path.cubicTo(5, size.height, 10, size.height,
15, size.height);
path.moveTo(15, size.height);
path.lineTo(size.width - 10, size.height);
path.cubicTo(size.width, size.height - 5, size.width, size.height - 10,
size.width, size.height - 15);
path.moveTo(size.width - 5, size.height);
path.close();
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Result:
Related
I want to give a shape to an image like below
.
here is my build widget
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Container(
height: 200,
color: Colors.grey,
),
ClipPath(
clipper: NativeClipper(),
child: Container(
width: double.maxFinite,
height: 200,
child: Image.asset('assets/classroom.png',fit: BoxFit.cover,),
),
),
],
),
)
);
}
and this is the native clipper function:
class NativeClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
Path path = Path();
path.lineTo(0, 0);
path.lineTo(0, size.height - 50);
path.quadraticBezierTo(size.width / 2, size.height, size.width, size.height - 50);
path.lineTo(size.width, 0);
path.lineTo(0, 0);
return path;
}
#override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
}
but that code only makes the bottom of shape.how can I make top of that image to be like its bottom?
how can I fix that?is it a good way to make it?
Try this :
class NativeClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
Path path = Path()
..cubicTo(0, 0, size.width / 2, 50, size.width, 0)
..lineTo(size.width, size.height - 50)
..cubicTo(size.width, size.height - 50, size.width / 2, size.height +
50, 0, size.height - 50);
return path;
}
#override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
}
You need to change getClip()
path.lineTo(0, 0);
path.lineTo(0, size.height - 50);
path.quadraticBezierTo(size.width / 2, size.height, size.width, size.height - 50);
path.lineTo(size.width, 0);
path.quadraticBezierTo(size.width / 2, size.height/2, 0, 0);
I hope this is what you wanted, based on the question you wrote.
i made this shape using CustumPainter Class , i want the container color to fill only the shape , like a full charged battery
this is how i made the shape
void paint(Canvas canvas, Size size) {
var paint = Paint();
var path = Path();
paint.color = Colors.black;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 4.0;
var posX;
var posY;
path.lineTo(size.width*0.75, 0);
path.lineTo(size.width*0.75, size.height*0.25);
path.lineTo(size.width*0.75, size.height);
path.lineTo(0, size.height);
path.lineTo(0, 0);
path.moveTo(size.width*0.75, size.height*0.25);
path.lineTo(size.width*0.80, size.height*0.25);
path.lineTo(size.width*0.80, size.height*0.75);
path.lineTo(size.width*0.75, size.height*0.75);
canvas.drawPath(path, paint);
}
and this is my widget
return ClipRRect(
child: Container(
width: 100,
color: Colors.red,
height: 50,
child: CustomPaint(
child: Container(
),
painter: BatteryPainter(),
),
),
);
Create another Path/rect inside Painter to handle fill color property , Also include Paint()..strokeCap = StrokeCap.round for better look on outer side.
, pass the value to control fill color.
class BatteryPainter extends CustomPainter {
final Color fillColor;
final double value;
BatteryPainter({
required this.value,
this.fillColor = Colors.red,
});
#override
void paint(Canvas canvas, Size size) {
var paint = Paint()..strokeCap = StrokeCap.round;
var path = Path();
paint.color = Colors.black;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 4.0;
path.lineTo(size.width * 0.75, 0);
path.lineTo(size.width * 0.75, size.height * 0.25);
path.lineTo(size.width * 0.75, size.height);
path.lineTo(0, size.height);
path.lineTo(0, 0);
path.moveTo(size.width * 0.75, size.height * 0.25);
path.lineTo(size.width * 0.80, size.height * 0.25);
path.lineTo(size.width * 0.80, size.height * 0.75);
path.lineTo(size.width * 0.75, size.height * 0.75);
Rect rect = Rect.fromLTWH(0, 0, size.width * 0.75 * value, size.height);
canvas.drawPath(path, paint);
canvas.drawRect(
rect,
Paint()
..color = fillColor
..style = PaintingStyle.fill);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
Use
Container(
width: 100,
height: 50,
child: CustomPaint(
painter: BatteryPainter(value: value),
),
),
To get a custom shape you must be using clipPath instead of clip Rect
ClipPath(
clipper: CustomPath(),
child: Container(
width: double.infinity,
height: 500,
color: Colors.amberAccent,
),
),
More about clipPath
How to create this corner-shaped card view in a flutter container..
You can archive this in several ways, using
Container Decoration
ClipPath
CustomPaint
Here is a demo of using CustomPaint, modify the value the way you like.
Result
Painter
class PriceTagPaint extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.green
..strokeCap = StrokeCap.round
..style = PaintingStyle.fill;
Path path = Path();
path
..moveTo(0, size.height * .5)
..lineTo(size.width * .13, 0)
..lineTo(size.width, 0)
..lineTo(size.width, size.height)
..lineTo(size.width * .13, size.height)
..lineTo(0, size.height * .5)
..close();
canvas.drawPath(path, paint);
//* Circle
canvas.drawCircle(
Offset(size.width * .13, size.height * .5),
size.height * .15,
paint..color = Colors.white,
);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
And use
SizedBox(
height: 100,
width: 300,
child: CustomPaint(
painter: PriceTagPaint(),
child: Center(
child: Text(
"Coolant",
style: TextStyle(
fontSize: 44,
),
),
),
),
);
Check on dartpad or on gist
Could you suggest my how to implement BottomAppBar with shape as you could see in picture bellow
I'm trying to wrap BottomAppBar with ClipRRect
return ClipRRect(
borderRadius: BorderRadius.vertical(
top: Radius.circular(40),
),
child: BottomAppBar(
key: widget.key,
shape: widget.notchedShape,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: items,
),
color: Colors.red, //widget.backgroundColor,
),
);
But result is not as I wish
You can use CustomPainter() and using that you can make your own design.
This is not perfect as you have shown by you but you can always tweak the setting on your own.
class MyCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint_0 = new Paint()
..color = Colors.white
..style = PaintingStyle.fill;
Path path_0 = Path();
path_0.moveTo(size.width * 0.0500000, size.height * 0.9000000);
path_0.cubicTo(
size.width * 0.5000000,
size.height * 0.8400000,
size.width * 0.4975000,
size.height * 0.8380000,
size.width * 0.9500000,
size.height * 0.9000000);
path_0.quadraticBezierTo(
size.width * 1, size.height * 0.9, size.width, size.height);
path_0.lineTo(0, size.height);
path_0.quadraticBezierTo(size.width * 0, size.height * 0.90,
size.width * 0.0500000, size.height * 0.9000000);
path_0.close();
canvas.drawPath(path_0, paint_0);
canvas.drawShadow(path_0, Color(0x68FFFFFF), 8, true);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
Output
I have to design screen like above image:
I want to draw white background portion in the above image. I have try by using custom paint with clip path but I can't achieve like the image.
Here is my code:
class CommomContainer extends CustomClipper<Path> {
CommomContainer({#required this.holeRadius});
final double holeRadius;
#override
Path getClip(Size size) {
final path = Path()
..moveTo(0, 0)
..lineTo(size.width / 2 - holeRadius - 10, 0.0)
..quadraticBezierTo(
size.width / 2 - holeRadius, 0.0, size.width / 2 - holeRadius, 10.0)
..arcToPoint(
Offset(size.width / 2 + holeRadius, 0.0),
clockwise: false,
radius: Radius.circular(2),
)
..lineTo(size.width, 0.0)
..lineTo(size.width, size.height);
path.lineTo(0.0, size.height);
path.close();
return path;
}
#override
bool shouldReclip(CommomContainer oldClipper) => true;
}
Any help is appreciated.
Here you can use Shape Maker and I used that too. You can change stroke style from PaintingStyle.stroke to PaintingStyle.fill to fill the desired color.
class MyCustomPainter extends CustomPainter{
#override
void paint(Canvas canvas, Size size) {
Paint paint_0 = new Paint()
..color = Color.fromARGB(255, 33, 150, 243)
..style = PaintingStyle.stroke
..strokeWidth = 1;
Path path_0 = Path();
path_0.moveTo(0,0);
path_0.lineTo(size.width,0);
path_0.lineTo(size.width,size.height);
path_0.lineTo(0,size.height);
path_0.lineTo(0,0);
path_0.close();
canvas.drawPath(path_0, paint_0);
Paint paint_1 = new Paint()
..color = Color.fromARGB(255, 33, 150, 243)
..style = PaintingStyle.stroke
..strokeWidth = 1;
Path path_1 = Path();
path_1.moveTo(size.width*0.3071375,size.height*0.3273600);
path_1.cubicTo(size.width*0.3067750,size.height*0.1999400,size.width*0.3815000,size.height*0.1964000,size.width*0.4125000,size.height*0.2000000);
path_1.cubicTo(size.width*0.4514375,size.height*0.3614200,size.width*0.5514000,size.height*0.3594200,size.width*0.5875000,size.height*0.2000000);
path_1.quadraticBezierTo(size.width*0.6656000,size.height*0.1954200,size.width*0.6943500,size.height*0.3273600);
path_1.quadraticBezierTo(size.width*0.6943500,size.height*0.6060200,size.width*0.6943500,size.height*0.6990200);
path_1.quadraticBezierTo(size.width*0.6943500,size.height*0.8229400,size.width*0.6169000,size.height*0.8229400);
path_1.quadraticBezierTo(size.width*0.4427250,size.height*0.8229400,size.width*0.3846250,size.height*0.8229400);
path_1.quadraticBezierTo(size.width*0.3049125,size.height*0.8229600,size.width*0.3071375,size.height*0.6990200);
path_1.quadraticBezierTo(size.width*0.3071375,size.height*0.6060200,size.width*0.3071375,size.height*0.3273600);
path_1.close();
canvas.drawPath(path_1, paint_1);
Paint paint_2 = new Paint()
..color = Color.fromARGB(255, 33, 150, 243)
..style = PaintingStyle.stroke
..strokeWidth = 1;
Path path_2 = Path();
path_2.moveTo(size.width*0.5000002,size.height*0.0804608);
path_2.cubicTo(size.width*0.5273750,size.height*0.0804200,size.width*0.5684875,size.height*0.1111200,size.width*0.5684620,size.height*0.1899997);
path_2.cubicTo(size.width*0.5684875,size.height*0.2338200,size.width*0.5479250,size.height*0.2995600,size.width*0.5000002,size.height*0.2995385);
path_2.cubicTo(size.width*0.4726125,size.height*0.2995600,size.width*0.4315250,size.height*0.2667000,size.width*0.4315384,size.height*0.1899997);
path_2.cubicTo(size.width*0.4315250,size.height*0.1462000,size.width*0.4520625,size.height*0.0804200,size.width*0.5000002,size.height*0.0804608);
path_2.close();
canvas.drawPath(path_2, paint_2);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
Try this, I have used stack and then I have put 2 concentric circle on top of rectangle.
Scaffold(
backgroundColor: Colors.yellow,
body: Center(
child: Stack(
alignment: Alignment.topCenter,
clipBehavior: Clip.none,
children: [
Card(
color: Colors.white,
child: Container(
height: 300,
width: 300,
),
),
Positioned(
top: -50,
child: Container(
height: 100,
width: 100,
// color: Colors.yellow,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.yellow),
),
),
Positioned(
top: -40,
child: Container(
height: 80,
width: 80,
// color: Colors.yellow,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
)
],
),));