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
I have this piece of code.
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(18),
),
child: Center(
child: Text(
'Monday',
style: TextStyle(
color: Colors.white,
fontSize: 30,
),
),
),
);
That produces this
But I want something that looks like this.
By Knowing CustomPainter widget's paint
class MyCustomPainter extends CustomPainter {
final double padding;
final double frameSFactor;
MyCustomPainter({
required this.padding,
required this.frameSFactor,
});
#override
void paint(Canvas canvas, Size size) {
final frameHWidth = size.width * frameSFactor;
Paint paint = Paint()
..color = Colors.redAccent
..strokeCap = StrokeCap.round
..style = PaintingStyle.fill
..strokeWidth = 4;
/// background
canvas.drawRRect(
RRect.fromRectAndRadius(
Rect.fromLTRB(0, 0, size.width, size.height),
Radius.circular(18),
),
paint);
/// top left
canvas.drawLine(
Offset(0 + padding, padding),
Offset(
padding + frameHWidth,
padding,
),
paint..color = Colors.black,
);
canvas.drawLine(
Offset(0 + padding, padding),
Offset(
padding,
padding + frameHWidth,
),
paint..color = Colors.black,
);
/// top Right
canvas.drawLine(
Offset(size.width - padding, padding),
Offset(size.width - padding - frameHWidth, padding),
paint..color = Colors.black,
);
canvas.drawLine(
Offset(size.width - padding, padding),
Offset(size.width - padding, padding + frameHWidth),
paint..color = Colors.black,
);
/// Bottom Right
canvas.drawLine(
Offset(size.width - padding, size.height - padding),
Offset(size.width - padding - frameHWidth, size.height - padding),
paint..color = Colors.black,
);
canvas.drawLine(
Offset(size.width - padding, size.height - padding),
Offset(size.width - padding, size.height - padding - frameHWidth),
paint..color = Colors.black,
);
/// Bottom Left
canvas.drawLine(
Offset(0 + padding, size.height - padding),
Offset(0 + padding + frameHWidth, size.height - padding),
paint..color = Colors.black,
);
canvas.drawLine(
Offset(0 + padding, size.height - padding),
Offset(0 + padding, size.height - padding - frameHWidth),
paint..color = Colors.black,
);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true; //based on your use-cases
}
And use Like
SizedBox(
height: 200,
width: 200,
child: CustomPaint(
painter: MyCustomPainter(frameSFactor: .1, padding: 20),
child: Center(
child: Text(
'With Painter',
style: TextStyle(
color: Colors.black,
fontSize: 30,
),
),
),
),
),
Also using Container decoration
class CustomDecoration extends Decoration {
final Color? backgroundColor;
final double frameSFactor;
//defalut padding _Need to check
final double gap;
CustomDecoration({
this.backgroundColor = Colors.transparent,
required this.frameSFactor,
required this.gap,
});
#override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
return CustomDecorationPainter(
backgroundColor: backgroundColor!,
frameSFactor: frameSFactor,
padding: gap);
}
}
class CustomDecorationPainter extends BoxPainter {
final Color backgroundColor;
final double frameSFactor;
final double padding;
CustomDecorationPainter({
required this.backgroundColor,
required this.frameSFactor,
required this.padding,
});
#override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
print(configuration.size!.height);
final Rect bounds = offset & configuration.size!;
final frameHWidth = configuration.size!.width * frameSFactor;
Paint paint = Paint()
..color = backgroundColor
..strokeCap = StrokeCap.round
..style = PaintingStyle.fill
..strokeWidth = 4;
/// background
canvas.drawRRect(
RRect.fromRectAndRadius(
bounds,
Radius.circular(18),
),
paint..color = Colors.redAccent);
paint.color = Colors.black;
/// top left
canvas.drawLine(
bounds.topLeft + Offset(padding, padding),
Offset(bounds.topLeft.dx + frameHWidth, bounds.topLeft.dy) +
Offset(padding, padding),
paint,
);
canvas.drawLine(
bounds.topLeft + Offset(padding, padding),
Offset(bounds.topLeft.dx, bounds.topLeft.dy + frameHWidth) +
Offset(padding, padding),
paint,
);
//top Right
canvas.drawLine(
Offset(bounds.topRight.dx - padding, bounds.topRight.dy + padding),
Offset(bounds.topRight.dx - padding - frameHWidth,
bounds.topRight.dy + padding),
paint,
);
canvas.drawLine(
Offset(bounds.topRight.dx - padding, bounds.topRight.dy + padding),
Offset(bounds.topRight.dx - padding,
bounds.topRight.dy + padding + frameHWidth),
paint..color,
);
//bottom Right
canvas.drawLine(
Offset(bounds.bottomRight.dx - padding, bounds.bottomRight.dy - padding),
Offset(bounds.bottomRight.dx - padding,
bounds.bottomRight.dy - padding - frameHWidth),
paint,
);
canvas.drawLine(
Offset(bounds.bottomRight.dx - padding, bounds.bottomRight.dy - padding),
Offset(bounds.bottomRight.dx - padding - frameHWidth,
bounds.bottomRight.dy - padding),
paint,
);
//bottom Left
canvas.drawLine(
Offset(bounds.bottomLeft.dx + padding, bounds.bottomLeft.dy - padding),
Offset(bounds.bottomLeft.dx + padding,
bounds.bottomLeft.dy - padding - frameHWidth),
paint,
);
canvas.drawLine(
Offset(bounds.bottomLeft.dx + padding, bounds.bottomLeft.dy - padding),
Offset(bounds.bottomLeft.dx + padding + frameHWidth,
bounds.bottomLeft.dy - padding),
paint,
);
}
}
And use like
SizedBox(
width: 200,
height: 200,
child: Container(
alignment: Alignment.center,
decoration: CustomDecoration(
frameSFactor: .1,
gap: 20,
),
child: Text("With Decoration"),
),
),
you can add the button the way you like
You have to write a CustomPainter class to achieve this, luckily there's a site which generates code for a given svg or use Nested Stack with Container. This example gives the one which you expected.
CustomPainter class
class RPSCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Path path_0 = Path();
path_0.moveTo(size.width * 0.1898734, 0);
path_0.lineTo(size.width * 0.06962025, 0);
path_0.cubicTo(size.width * 0.03117006, 0, 0, size.height * 0.03117006, 0,
size.height * 0.06962025);
path_0.lineTo(0, size.height * 0.1835443);
path_0.lineTo(size.width * 0.02531646, size.height * 0.1835443);
path_0.lineTo(size.width * 0.02531646, size.height * 0.06962025);
path_0.cubicTo(
size.width * 0.02531646,
size.height * 0.04515196,
size.width * 0.04515196,
size.height * 0.02531646,
size.width * 0.06962025,
size.height * 0.02531646);
path_0.lineTo(size.width * 0.1898734, size.height * 0.02531646);
path_0.lineTo(size.width * 0.1898734, 0);
path_0.close();
path_0.moveTo(size.width * 0.1898734, size.height * 0.9746835);
path_0.lineTo(size.width * 0.06962025, size.height * 0.9746835);
path_0.cubicTo(
size.width * 0.04515196,
size.height * 0.9746835,
size.width * 0.02531646,
size.height * 0.9548481,
size.width * 0.02531646,
size.height * 0.9303797);
path_0.lineTo(size.width * 0.02531646, size.height * 0.8164557);
path_0.lineTo(0, size.height * 0.8164557);
path_0.lineTo(0, size.height * 0.9303797);
path_0.cubicTo(0, size.height * 0.9688291, size.width * 0.03117006,
size.height, size.width * 0.06962025, size.height);
path_0.lineTo(size.width * 0.1898734, size.height);
path_0.lineTo(size.width * 0.1898734, size.height * 0.9746835);
path_0.close();
path_0.moveTo(size.width * 0.8227848, size.height);
path_0.lineTo(size.width * 0.8227848, size.height * 0.9746835);
path_0.lineTo(size.width * 0.9303797, size.height * 0.9746835);
path_0.cubicTo(
size.width * 0.9548481,
size.height * 0.9746835,
size.width * 0.9746835,
size.height * 0.9548481,
size.width * 0.9746835,
size.height * 0.9303797);
path_0.lineTo(size.width * 0.9746835, size.height * 0.8164557);
path_0.lineTo(size.width, size.height * 0.8164557);
path_0.lineTo(size.width, size.height * 0.9303797);
path_0.cubicTo(size.width, size.height * 0.9688291, size.width * 0.9688291,
size.height, size.width * 0.9303797, size.height);
path_0.lineTo(size.width * 0.8227848, size.height);
path_0.close();
path_0.moveTo(size.width * 0.8227848, size.height * 0.02531646);
path_0.lineTo(size.width * 0.8227848, 0);
path_0.lineTo(size.width * 0.9303797, 0);
path_0.cubicTo(size.width * 0.9688291, 0, size.width,
size.height * 0.03117006, size.width, size.height * 0.06962025);
path_0.lineTo(size.width, size.height * 0.1835443);
path_0.lineTo(size.width * 0.9746835, size.height * 0.1835443);
path_0.lineTo(size.width * 0.9746835, size.height * 0.06962025);
path_0.cubicTo(
size.width * 0.9746835,
size.height * 0.04515196,
size.width * 0.9548481,
size.height * 0.02531646,
size.width * 0.9303797,
size.height * 0.02531646);
path_0.lineTo(size.width * 0.8227848, size.height * 0.02531646);
path_0.close();
Paint paint_0_fill = Paint()..style = PaintingStyle.fill;
paint_0_fill.color = Color(0xff181717).withOpacity(1.0);
canvas.drawPath(path_0, paint_0_fill);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
and use it like so
Stack(
alignment: Alignment.bottomCenter,
children: [
Stack(
alignment: Alignment.center,
children: [
Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(18),
),
child: Center(
child: Text(
'Monday',
style: TextStyle(
color: Colors.white,
fontSize: 30,
),
),
),
),
Padding(
padding: EdgeInsets.all(24),
child: CustomPaint(
size: Size(180, 180),
painter: RPSCustomPainter(),
),
),
],
),
Padding(
padding: EdgeInsets.only(bottom: 24),
child: ClipRRect(
borderRadius: BorderRadius.circular(100),
child: Container(
padding: EdgeInsets.all(4),
color: Colors.black,
child: Icon(
Icons.close,
color: Colors.white,
size: 16,
),
),
),
),
],
),
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
My current code :
Container(
height: 1 / 3 * deviceSize.height,
width: double.infinity,
child: Text(
'Add New Location',
style: TextStyle(color: Colors.black, fontSize: 20.0),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.elliptical(300, 100),
bottomRight: Radius.elliptical(300, 100)),
color: Color(0xFFFAD02E),
),
)
I am not getting desired results.... :/
You can Try ClipPath using custom clipper to make this desire UI in flutter. But Your Method can still work need some tweaking.
ClipPath(
clipper: ProfileClipper(),
child: Image(
height: 300.0,
width: double.infinity,
image: AssetImage('You can use image or your desire color use container'),
fit: BoxFit.cover,
),
),
import 'package:flutter/material.dart';
class ProfileClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
Path path = Path();
path.lineTo(0, 4 * size.height / 5);
Offset curvePoint = Offset(size.width / 2, size.height);
Offset endPoint = Offset(size.width, 4 * size.height / 5);
path.quadraticBezierTo(
curvePoint.dx,
curvePoint.dy,
endPoint.dx,
endPoint.dy,
);
path.lineTo(size.width, 0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return false;
}
}
You can use ClipPath
Try this
ClipPath(
clipper: BottomClipper(),
child: Container(
height: 200,
color: Colors.yellow,
child: Center(child: Text("BottomClipper()")),
),
),
BottomClipper()
import 'package:flutter/material.dart';
class BottomClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, 0);
path.lineTo(0, size.height - 40);
path.quadraticBezierTo(
size.width / 4, size.height, size.width / 2, size.height);
path.quadraticBezierTo(
size.width - size.width / 4, size.height, size.width, size.height - 40);
path.lineTo(size.width, 0);
path.lineTo(0, 0);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return true;
}
}
OUTPUT
I want to build this
I used a ClipPath like this:
ClipPath(
clipper: HeaderClipper(),
child: Image.asset(
"assets/images/stores/bg1.jpg",
fit: BoxFit.cover,
),
),
And this is my HeaderClipper class:
class HeaderClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
final path = Path();
final heightFactor = 5 / 8;
path.lineTo(0, size.height * heightFactor);
path.quadraticBezierTo(
50,
size.height,
size.width / 4,
size.height,
);
path.lineTo(size.width * (3 / 4), size.height);
path.quadraticBezierTo(
size.width - 50,
size.height,
size.width,
size.height * heightFactor,
);
path.lineTo(size.width, 0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
But I don't know why it doesn't look like the picture. Can you help me what parameters should I change or should I use another method instead of quadraticBezierTo?
You can simply achieve it using - ClipRRect
Code:
ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(140.0),
bottomRight: Radius.circular(140.0)),
child: Container(
child:
Image(image: NetworkImage('https://placeimg.com/640/480/people')),
),
)