How can I draw something like this inside a container in flutter?.
PS I am new to flutter.
Thanks in advance.
You can try this, the idea is using multiple quadraticBezierTo. Remember that B, C, D should be on the same line to make the joint smooth:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Container(
width: 300,
height: 700,
color: Colors.yellow,
child: CustomPaint(painter: FaceOutlinePainter()),
),
),
),
);
}
}
class FaceOutlinePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
path.moveTo(size.width / 2, 0); //Ax, Ay
path.quadraticBezierTo(size.width, size.height / 8, size.width / 2, size.height / 4); //Bx, By, Cx, Cy
path.quadraticBezierTo(0, 3 * size.height / 8, size.width / 2, size.height / 2); //Dx, Dy, Ex, Ey
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(FaceOutlinePainter oldDelegate) => false;
}
Related
how to add image inside of CustomPainter and manage.
like this:
import 'package:flutter/material.dart';
import 'package:hallo/appbar.dart';
class product1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body:Stack(
children: [
Column(
children: [
CustomPaint(
size: Size.fromHeight(500),
painter: RPSCustomPainter(),
),
Container(
)
],
)
],
)
);
}
}
class RPSCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint0 = Paint()
..color = const Color.fromARGB(255, 33, 150, 243)
..style = PaintingStyle.stroke
..strokeWidth = 1.0;
Path path0 = Path();
path0.moveTo(0,0);
path0.lineTo(0,size.height);
path0.quadraticBezierTo(size.width*0.1120000,size.height*0.7968571,size.width*0.3375000,size.height*0.8585714);
path0.cubicTo(size.width*0.5795625,size.height*0.9350714,size.width*0.8043750,size.height*1.0775000,size.width,size.height);
path0.quadraticBezierTo(size.width,size.height*0.7500000,size.width,0);
path0.lineTo(size.width*0.1252500,0);
path0.lineTo(0,0);
path0.close();
canvas.drawPath(path0, paint0);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
try this:
class HomeScreen extends StatelessWidget {
const HomeScreen({
super.key,
});
static const String route = "/homeScreen";
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(
height: MediaQuery.of(context).size.height * 0.5,
child: Image.network(
"https://images.pexels.com/photos/14446269/pexels-photo-14446269.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
fit: BoxFit.cover,
width: double.infinity,
),
),
CustomPaint(
size: MediaQuery.of(context).size,
painter: RPSCustomPainter(),
),
],
),
);
}
}
class RPSCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint0 = Paint()
..color = const Color.fromARGB(255, 33, 150, 243)
..style = PaintingStyle.fill
..strokeWidth = 5.0;
Path path1 = Path();
path1.moveTo(0, size.height);
path1.lineTo(0, size.height * 0.5);
path1.quadraticBezierTo(
size.width * 0.1120000,
size.height * 0.5 * 0.7968571,
size.width * 0.3375000,
size.height * 0.5 * 0.8585714);
path1.cubicTo(
size.width * 0.5795625,
size.height * 0.5 * 0.9350714,
size.width * 0.8043750,
size.height * 0.5 * 1.0775000,
size.width,
size.height * 0.5,
);
path1.lineTo(size.width, size.height);
path1.lineTo(0, size.height);
path1.close();
canvas.drawPath(path1, paint0);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
you will get this type of results:
I have a CustomPaint which paints an oval.
I want to cut out a hole at a specific position which I couldn't figure out yet how that works.
I tried:
canvas.drawPath(
Path.combine(PathOperation.difference, ovalPath, holePath),
ovalPaint,
);
but that doesn't cut the hole, but gives me the following result:
But this is what I want to achieve:
This oval is just an example, the "real" custom paint is gonna get more complex and I need more than just one cutout. So just painting several lines is not an alternative. I want to first define the path and then apply a cutout (or even inverted clipping) to get the hole.
Is that possible?
Here is a full working example of what I have:
import 'package:flutter/material.dart';
import 'dart:math';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: OvalCustomPaint(),
),
),
);
}
}
class OvalCustomPaint extends StatelessWidget {
const OvalCustomPaint({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: LayoutBuilder(
builder: (context, constraints) {
return Center(
child: CustomPaint(
painter: _Painter(),
child: SizedBox(
width: constraints.maxWidth,
height: constraints.maxHeight,
),
),
);
},
),
);
}
}
class _Painter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
canvas.translate(size.width / 2, size.height / 2);
const curveRadius = 50.0;
const legLength = 150.0;
canvas.rotate(pi/2);
final ovalPaint = Paint()
..color = Colors.blue
..strokeWidth = 2.5
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
const fixPoint = Offset.zero;
//* OVAL LINE
final ovalPath = Path()..moveTo(fixPoint.dx, fixPoint.dy);
ovalPath.relativeArcToPoint(
const Offset(curveRadius * 2, 0),
radius: const Radius.circular(curveRadius),
);
ovalPath.relativeLineTo(0, legLength);
ovalPath.relativeArcToPoint(
const Offset(-curveRadius * 2, 0),
radius: const Radius.circular(curveRadius),
);
ovalPath.relativeLineTo(0, -legLength);
//* CLP HOLE
final holePath = Path();
holePath.addArc(Rect.fromCircle(center: fixPoint, radius: 13), 0, 2 * pi);
canvas.drawPath(
Path.combine(PathOperation.difference, ovalPath, holePath),
ovalPaint,
);
}
#override
bool shouldRepaint(_Painter oldDelegate) => false;
}
Okay I found a solution for it.
I created a rect path with the size of the CustomPainter area and built the difference with the cutout hole path.
That created a cutout template:
final rectWithCutout = Path.combine(
PathOperation.difference,
Path()
..addRect(
Rect.fromCenter(
center: Offset.zero,
width: size.width,
height: size.height,
),
),
holePath);
Which I could clip the canvas with: canvas.clipPath(rectWithCutout);
The final result:
This is the working full code example again:
import 'dart:math';
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: OvalCustomPaint(),
),
),
);
}
}
class OvalCustomPaint extends StatelessWidget {
const OvalCustomPaint({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: LayoutBuilder(
builder: (context, constraints) {
return Center(
child: CustomPaint(
painter: _Painter(),
child: SizedBox(
width: constraints.maxWidth,
height: constraints.maxHeight,
),
),
);
},
),
);
}
}
class _Painter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
canvas.translate(size.width / 2, size.height / 2);
const curveRadius = 40.0;
const legLength = 130.0;
canvas.rotate(pi / 2);
final ovalPaint = Paint()
..color = Colors.blue
..strokeWidth = 2.5
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
const fixPoint = Offset.zero;
//* OVAL LINE
final ovalPath = Path()..moveTo(fixPoint.dx, fixPoint.dy);
ovalPath.relativeArcToPoint(
const Offset(curveRadius * 2, 0),
radius: const Radius.circular(curveRadius),
);
ovalPath.relativeLineTo(0, legLength);
ovalPath.relativeArcToPoint(
const Offset(-curveRadius * 2, 0),
radius: const Radius.circular(curveRadius),
);
ovalPath.relativeLineTo(0, -legLength);
//* CLIP HOLE
final holePath = Path();
holePath.addArc(Rect.fromCircle(center: fixPoint, radius: 13), 0, 2 * pi);
final rectWithCutout = Path.combine(
PathOperation.difference,
Path()
..addRect(
Rect.fromCenter(
center: Offset.zero,
width: size.width,
height: size.height,
),
),
holePath);
canvas.clipPath(rectWithCutout);
canvas.drawPath(
ovalPath,
ovalPaint,
);
}
#override
bool shouldRepaint(_Painter oldDelegate) => false;
}
You can control the length of the line.
ovalPath.relativeArcToPoint(
const Offset(-curveRadius * 2, 0),
radius: const Radius.circular(curveRadius),
);
ovalPath.relativeLineTo(0, -legLength + (13 * 2)); //here based on radius
canvas.drawPath(
ovalPath,
ovalPaint,
);
I'm trying to achieve shape in the shown image. I can't find out how to do this. Last thing I tried was:
Container(
height: 175,
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(
bottom: Radius.elliptical(175, 45),
),
),
)
How can I create this shape?
You can use custom painter:
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Container(
color: Colors.transparent,
height: 155,
width: 375,
child: CustomPaint(
painter: CurvePainter(),
),
),
);
}
}
class CurvePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
var paint = Paint();
paint.color = Color(0XFF382b47);
paint.style = PaintingStyle.fill;
var path = Path();
path.moveTo(0, size.height * 0.26);
path.quadraticBezierTo(
size.width / 2, size.height, size.width, size.height * 0.26);
path.lineTo(size.width, 0);
path.lineTo(0, 0);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
View Image
If you want to add ovel shape on top borders:
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Transform(
alignment: Alignment.center,
transform: Matrix4.rotationX(math.pi),
child: Container(
color: Colors.red,
height: 120,
width: double.infinity,
child: CustomPaint(
painter: CurvePainter(),
),
),
),;
}
}
class CurvePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
var paint = Paint();
paint.color = Color(0XFF382b47);
paint.style = PaintingStyle.fill;
var path = Path();
path.moveTo(0, size.height * 0.26);
path.quadraticBezierTo(
size.width / 2, size.height, size.width, size.height * 0.26);
path.lineTo(size.width, 0);
path.lineTo(0, 0);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
this is the custom shape code
class SignInPageCustomShape extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final paint = Paint();
final Color myColor = Colors.black12;
paint.color = myColor;
paint.style = PaintingStyle.fill;
final path = Path();
path.moveTo(0, size.height * 0.9167);
path.quadraticBezierTo(
size.width * 0.25,
size.height * 0.875,
size.width * 0.5,
size.height * 0.9167,
);
path.quadraticBezierTo(
size.width * 0.75,
size.height * 0.9584,
size.width * 1.0,
size.height * 0.9167,
);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
and this is my widget tree,I don't know what is wrong, I tried to put my container in different places, but the same result is gotten, stack overflow is asking me to explain more, but I haven't anything else to explain .
class Paint extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.white,
child: CustomPaint(
painter: SignInPageCustomShape(),
),
),
),
);
}
}
The issue that you are facing might be because you haven't defined a child in CustomPaint
I added an empty Container and run the code and got this results
Screenshot
Naming your StatelessWidget Paint is not recommended also
class Paint extends StatelessWidget {
The following method accepts two parameters one of type Paint because you defined a custom widget with the same name it was passing the wrong parameter in my case
canvas.drawPath(path, paint);
Code I used to get the results attached in this response:
Paint Widget:
class PaintWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.white,
child: CustomPaint(
painter: SignInPageCustomShape(),
child: Container(),
),
),
),
);
}
}
SignInPageCustomShape Widget:
class SignInPageCustomShape extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final paint = Paint();
final Color myColor = Colors.black12;
paint.color = myColor;
paint.style = PaintingStyle.fill;
final path = Path();
path.moveTo(0, size.height * 0.9167);
path.quadraticBezierTo(
size.width * 0.25,
size.height * 0.875,
size.width * 0.5,
size.height * 0.9167,
);
path.quadraticBezierTo(
size.width * 0.75,
size.height * 0.9584,
size.width * 1.0,
size.height * 0.9167,
);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
My UI draw like this picture:
So I write some code by using CodePainter in Flutter. Here's my code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class BackgroundShape extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint();
paint.color = Colors.black;
var smallRect = Alignment.bottomCenter.inscribe(Size(100, 50), Rect.fromLTWH(size.width/2 -35, size.height-40, 40, 30));
var path = Path();
path.fillType = PathFillType.evenOdd;
path.addRRect(RRect.fromRectAndCorners(Rect.fromLTWH(0, 0, size.width, size.height), bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10)));
path.addRRect(RRect.fromRectAndCorners(smallRect, topLeft: Radius.circular(10), topRight: Radius.circular(10)));
path.lineTo(0, size.height);
path.lineTo(size.width/2 - 35, size.height);
path.lineTo(size.width/2 - 35, size.height-40);
path.lineTo(size.width/2 + 35, size.height-40);
path.lineTo(size.width/2 + 35, size.height);
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0);
path.close();
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Here is my result:
How to add border radius? please help me :D thanks!
For some reason, I'm not able to run completely the code you've provided, but taking consideration your current requirements and from the comments. I've created the following samples for your references:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo'),
),
body: Center(
child: Container(
width: 200,
height: 200,
child: CustomPaint(
painter: PainterTwo(),
),
),
),
);
}
}
class PainterOne extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
double w = size.width;
double h = size.height;
double r = 15;
var paint1 = Paint()
..color = Color(0xff888888)
..style = PaintingStyle.fill;
RRect fullRect = RRect.fromRectAndRadius(
Rect.fromCenter(center: Offset(w / 2, h / 2), width: w, height: h),
Radius.circular(r),
);
canvas.drawRRect(fullRect, paint1);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
class PainterTwo extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.blue
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
path.addRRect(RRect.fromRectAndRadius(
Rect.fromLTWH(
size.width / 2, size.height / 2, size.width / 4, size.height / 4),
Radius.circular(15)));
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Output of PainterOne():
Output of PainterTwo():