Quarter Circle does not fit my initial circle Flutter Painter - flutter

I'm trying to make a loading icon for my loading screen using CustomPaint widget. Unfortunally, it doesn't work as expected...
My quarter circle does not fit in my primary circle, here's a screen of it :
I don't understand why it is doing this...
Here's the code:
import 'package:flutter/material.dart';
import 'package:responsive_sizer/responsive_sizer.dart';
import 'dart:math' as math;
class LoadingPage extends StatelessWidget {
const LoadingPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 25.h,
),
Stack(
alignment: Alignment.center,
children: [
Container(
width: 28.w,
height: 28.w,
decoration: BoxDecoration(
color: Colors.transparent,
shape: BoxShape.circle,
border: Border.all(width: 3.w, color: Colors.white.withOpacity(0.2)),
),
),
CustomPaint(
painter: MyPainter(),
size: Size(28.w, 28.w),
),
]
),
SizedBox(
height: 6.h,
),
Text(
"LOADING",
style: Theme.of(context).textTheme.headline2,
)
],
);
}
}
class MyPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..strokeWidth = 3.w
..style = PaintingStyle.stroke
..color = Colors.blue;
double degToRad(double deg) => deg * (math.pi / 180.0);
final path = Path()
..arcTo(
Rect.fromCircle(
center: Offset(size.width/2, size.height/2),
radius: 28.w/2,
),
degToRad(90),
degToRad(90),
false);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Does anyone knows why ? :)
Thanks for your answers,
Chris

Related

How to add arrow at bottom of a message box in flutter?

Please help me on how can I create this box
message box to be created in flutter
you ca use these packages to have a bubble shape for a message
bubble: ^1.2.1
flutter_chat_bubble: ^2.0.0
You can use the bubble from material design by importing
import 'package:flutter/material.dart';
or simply :-
Bubble(
margin: BubbleEdges.only(leftBottom: 10),
nip: BubbleNip.rightTop,
color: Color.fromRGBO(225, 255, 199, 1.0),
child: Text('Your Text', textAlign: TextAlign.right)
If u need more reference read this.
you can use customPainter or CustomClipper , in this case, better use clipper because we need all size from its child,
code :
import 'package:flutter/material.dart';
class MessageBox extends StatefulWidget {
const MessageBox({Key? key}) : super(key: key);
#override
_MessageBoxState createState() => _MessageBoxState();
}
class _MessageBoxState extends State<MessageBox> {
#override
Widget build(BuildContext context) {
return Material(
child: Column(
children: [
const SizedBox(height: 200,),
Container(
width: MediaQuery.of(context).size.width,
height: 100,
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(35.0)
),
),
ClipPath(
clipper: MessageClipper(),
child: Container(
height: 20,
width: MediaQuery.of(context).size.width,
color: Colors.purple,
),
)
],
),
);
}
}
class MessageClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var firstOffset = Offset(size.width * 0.1, 0.0);
var secondPoint = Offset(size.width * 0.15, size.height );
var lastPoint = Offset(size.width * 0.2, 0.0);
var path = Path()
..moveTo(firstOffset.dx, firstOffset.dy)
..lineTo(secondPoint.dx, secondPoint.dy)
..lineTo(lastPoint.dx, lastPoint.dy)
..close();
return path;
}
#override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return true;
}
}
here result :

Flutter custom shape using CustomPaint

I just want my created shape so that i can stack a widget to achieve the Image below. i am trying to get the transparent shape at the back ground of the X and Love. I Try using the shape maker but my mouse designing is not perfect. here is the code generated from the shape maker
child: CustomPaint(
size: Size(400,(400*0.2857142857142857).toDouble()),
painter: RPSCustomPainter(),
),
class RPSCustomPainter 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(size.width*0.2137714,size.height*0.2524000);
path_0.cubicTo(size.width*0.1736143,size.height*0.4775500,size.width*0.1973000,size.height*0.6711500,size.width*0.2153286,size.height*0.7510000);
path_0.cubicTo(size.width*0.2270429,size.height*0.7777500,size.width*0.2705286,size.height*0.9439500,size.width*0.3556000,size.height*0.7521500);
path_0.cubicTo(size.width*0.3856000,size.height*0.6504000,size.width*0.3970143,size.height*0.6162000,size.width*0.4283571,size.height*0.7526000);
path_0.cubicTo(size.width*0.4669286,size.height*0.8264000,size.width*0.5172429,size.height*0.9022500,size.width*0.5719714,size.height*0.7500000);
path_0.cubicTo(size.width*0.6146429,size.height*0.5440500,size.width*0.5914429,size.height*0.3101000,size.width*0.5713714,size.height*0.2514000);
path_0.cubicTo(size.width*0.5520714,size.height*0.1778000,size.width*0.4875429,size.height*0.0767500,size.width*0.4296571,size.height*0.2527000);
path_0.cubicTo(size.width*0.4023714,size.height*0.3646000,size.width*0.3816857,size.height*0.3850000,size.width*0.3557143,size.height*0.2523000);
path_0.cubicTo(size.width*0.3438571,size.height*0.2086000,size.width*0.2652143,size.height*0.0579000,size.width*0.2137714,size.height*0.2524000);
path_0.close();
canvas.drawPath(path_0, paint_0);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
what i am trying to achieve
my result. the shape is not perfect.
thanks
At first I wanted to describe you the ways you can achieve the shape you want and so on...
But got carried away with this fun programming challenge and ended up creating an actual widget :)
It depends on the font_awesome_flutter package, so don't forget to install it (for the heart icon). font_awesome_flutter
So the widget's source code is:
import 'package:flutter/material.dart';
import 'dart:math' as math;
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
extension ToRadians on int {
double get toRadians => this * (math.pi / 180.0);
}
enum _ButtonType { like, dislike }
class LikeOrNot extends StatelessWidget {
final VoidCallback onLike;
final VoidCallback onDislike;
// Percents from total widget width, default - 2%
final _gapSizeRatio = 0.02;
final _likeIconColor = const Color(0xffb85076);
final _dislikeIconColor = Colors.white;
const LikeOrNot({
Key? key,
required this.onLike,
required this.onDislike,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 2,
child: LayoutBuilder(
builder: (context, constraints) {
final buttonPaddings = constraints.maxHeight * 0.1;
final halfWidth = constraints.maxWidth / 2;
return Stack(
children: [
Positioned.fill(
child: CustomPaint(
painter: RPSCustomPainter(
gapSizeRatio: _gapSizeRatio,
),
),
),
Positioned(
left: 0,
bottom: 0,
top: 0,
right: halfWidth + constraints.maxWidth * _gapSizeRatio,
child: SizedBox.expand(
child: Padding(
padding: EdgeInsets.all(buttonPaddings),
child: _buildButton(_ButtonType.dislike),
),
),
),
Positioned(
right: 0,
bottom: 0,
top: 0,
left: halfWidth + constraints.maxWidth * _gapSizeRatio,
child: SizedBox.expand(
child: Padding(
padding: EdgeInsets.all(buttonPaddings),
child: _buildButton(_ButtonType.like),
),
),
),
],
);
},
),
);
}
Widget _buildButton(_ButtonType buttonType) {
final isPositiveAction = buttonType == _ButtonType.like;
return ElevatedButton(
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
primary: isPositiveAction ? _dislikeIconColor : _likeIconColor,
onPrimary: isPositiveAction ? _likeIconColor : _dislikeIconColor,
padding: EdgeInsets.zero,
elevation: 10,
shadowColor: Colors.black54,
),
onPressed: onDislike,
child: FractionallySizedBox(
widthFactor: 0.35,
heightFactor: 0.35,
child: FittedBox(
child: isPositiveAction
? const FaIcon(FontAwesomeIcons.heart)
: const Icon(Icons.close),
),
),
);
}
}
class RPSCustomPainter extends CustomPainter {
final double gapSizeRatio;
RPSCustomPainter({
required this.gapSizeRatio,
});
#override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.black.withOpacity(0.08)
..style = PaintingStyle.fill
..strokeWidth = 1;
final path = Path();
final gapSize = size.width * gapSizeRatio;
final arcRadius = size.height / 2 - gapSize / 2;
final leftCircleCenter = Offset(
size.width * 0.25 - gapSize / 2,
size.height / 2,
);
final rightCircleCenter = Offset(
size.width * 0.75 + gapSize / 2,
size.height / 2,
);
path.arcTo(
Rect.fromCircle(
center: leftCircleCenter,
radius: arcRadius,
),
45.toRadians,
270.toRadians,
false,
);
final bezierOffset = arcRadius * (105 / 360);
path.quadraticBezierTo(
size.width / 2,
size.height * 0.30,
rightCircleCenter.dx - arcRadius + bezierOffset,
rightCircleCenter.dy - arcRadius + bezierOffset,
);
path.arcTo(
Rect.fromCircle(
center: rightCircleCenter,
radius: arcRadius,
),
225.toRadians,
270.toRadians,
false,
);
path.quadraticBezierTo(
size.width / 2,
size.height * 0.70,
leftCircleCenter.dx + arcRadius - bezierOffset,
leftCircleCenter.dy + arcRadius - bezierOffset,
);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
It's dynamic, the buttons are built-in. You get 2 options to work with - onDislike() and onLike() callbacks.
An example using different sizes.
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffc0496f), Color(0xffdb6b59)],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: const Text('Test'),
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Container(
width: double.infinity,
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
for (final size in List.generate(5, (index) => index++))
FractionallySizedBox(
widthFactor: 1.0 - size * 0.2,
child: LikeOrNot(
onLike: () {},
onDislike: () {},
),
),
],
),
),
),
);
}
}
There's a _gapSize parameter which is the gap between two circles. The one you need is already inside (2% default) but you can get some cool other variations by changing it. For example, here's a gap of 20% total width:

Flutter _debugLifecycleState != _ElementLifecycle.defunct': is not true

I am showing some animated custom painter progress bar in my app it's showing some error
Error: The following assertion was thrown while notifying listeners for AnimationController:
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4263 pos 12: '_debugLifecycleState != _ElementLifecycle.defunct': is not true.
I have a simple homePage in which I have a navigation bar. I am simply showing the container when navigation change like this
SingleChildScrollView(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/sidebg.png"),
fit: BoxFit.cover,
),
),
child: Column(
children: [
pageIndex == 0 ? DashboardScreen() : Container(),
pageIndex == 1 ? MapScreen() : Container(),
pageIndex == 3 ? ServiceCenter() : Container(),
pageIndex == 4 ? ProfileScreen() : Container(),
],
)),
),
Issue is as you can see pages changes when index are changing but when i change the page its showing an error as i mention above in continuesly loop not stopping.
If I remove this progress indicator all is working fine.
This is the progress indicator screen
import 'dart:math' as math;
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
import 'package:sleek_circular_slider/sleek_circular_slider.dart';
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
class DashboardScreen extends StatefulWidget {
#override
_DashboardScreenState createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Container(
child: Column(
children: [
SizedBox(
height: height * 0.05,
),
Circular_arc(),
],
),
);
}
}
final Gradient gradient = new LinearGradient(
colors: <Color>[
Colors.greenAccent.withOpacity(1.0),
Colors.yellowAccent.withOpacity(1.0),
Colors.redAccent.withOpacity(1.0),
],
stops: [
0.0,
0.5,
1.0,
],
);
class Circular_arc extends StatefulWidget {
const Circular_arc({
Key key,
}) : super(key: key);
#override
_Circular_arcState createState() => _Circular_arcState();
}
class _Circular_arcState extends State<Circular_arc>
with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController animController;
#override
void initState() {
// TODO: implement initState
super.initState();
animController =
AnimationController(duration: Duration(seconds: 3), vsync: this);
final curvedAnimation =
CurvedAnimation(parent: animController, curve: Curves.easeInOutCubic);
animation = Tween<double>(begin: 0.0, end: 2).animate(curvedAnimation)
..addListener(() {
setState(() {});
});
animController.repeat(max: 1);
}
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Container(
child: Stack(
children: [
CustomPaint(
size: Size(300, 300),
painter: ProgressArc(null, Colors.black54, true),
),
CustomPaint(
size: Size(300, 300),
painter: ProgressArc(animation.value, Colors.redAccent, false),
),
Positioned(
top: height * 0.07,
left: width * 0.2,
child: Column(
children: [
Image.asset(
'images/star-icon-fill#3x.png',
height: height * 0.045,
),
RichText(
text: new TextSpan(
// Note: Styles for TextSpans must be explicitly defined.
// Child text spans will inherit styles from parent
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
new TextSpan(
text: '4.6',
style: new TextStyle(
fontSize: 40, fontFamily: 'UbuntuRegular')),
new TextSpan(
text: ' /5',
style: TextStyle(
fontSize: 25,
color: Colors.grey[400],
fontFamily: 'UbuntuRegular')),
],
),
),
Text(
'FIFTEEN DAYS SCORE',
style: TextStyle(
color: Colors.grey[400], fontFamily: 'UbuntuMedium'),
)
],
),
)
],
),
);
}
}
class ProgressArc extends CustomPainter {
bool isBackground;
double arc;
Color progressColor;
ProgressArc(this.arc, this.progressColor, this.isBackground);
#override
void paint(Canvas canvas, Size size) {
final rect = Rect.fromLTRB(0, 0, 300, 300);
final startAngle = -math.pi;
final sweepAngle = arc != null ? arc : math.pi;
final userCenter = false;
final paint = Paint()
..strokeCap = StrokeCap.round
..color = progressColor
..style = PaintingStyle.stroke
..strokeWidth = 10;
if (!isBackground) {
paint.shader = gradient.createShader(rect);
}
canvas.drawArc(rect, startAngle, sweepAngle, userCenter, paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
}
Error is in the continuous loop it's not stopping. And also its starts when I change the page index (mean when I change the navigation from home).
In your _CircularArcState, please...
Call animController.forward(); after animController.repeat(max: 1);
To save the state of CircularArc, add mixin AutomaticKeepAliveClientMixin in _CircularArcState. Then override wantKeepAlive and return true. Also, call super.build(context); inside build(...).
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: PageView(
scrollDirection: Axis.vertical,
children: [
DashboardScreen(),
Container(color: Colors.orange),
Container(color: Colors.blue),
Container(color: Colors.green),
],
),
),
);
}
}
class DashboardScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Container(
child: Column(
children: [
SizedBox(
height: height * 0.05,
),
CircularArc(),
],
),
);
}
}
final Gradient gradient = new LinearGradient(
colors: <Color>[
Colors.greenAccent.withOpacity(1.0),
Colors.yellowAccent.withOpacity(1.0),
Colors.redAccent.withOpacity(1.0),
],
stops: [0.0, 0.5, 1.0],
);
class CircularArc extends StatefulWidget {
const CircularArc({
Key key,
}) : super(key: key);
#override
_CircularArcState createState() => _CircularArcState();
}
class _CircularArcState extends State<CircularArc>
with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
double width;
double height;
Animation<double> animation;
#override
void initState() {
super.initState();
final AnimationController animController =
AnimationController(duration: Duration(seconds: 3), vsync: this);
final curvedAnimation =
CurvedAnimation(parent: animController, curve: Curves.easeInOutCubic);
animation = Tween<double>(begin: 0.0, end: 2).animate(curvedAnimation)
..addListener(() {
setState(() {});
});
animController.repeat(max: 1);
animController.forward();
}
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
if (width == null && height == null) {
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
}
return Container(
child: Stack(
children: [
CustomPaint(
size: Size(300, 300),
painter: ProgressArc(null, Colors.black54, true),
),
CustomPaint(
size: Size(300, 300),
painter: ProgressArc(animation.value, Colors.redAccent, false),
),
Positioned(
top: height * 0.07,
left: width * 0.2,
child: Column(
children: [
// Image.asset(
// 'images/star-icon-fill#3x.png',
// height: height * 0.045,
// ),
RichText(
text: new TextSpan(
// Note: Styles for TextSpans must be explicitly defined.
// Child text spans will inherit styles from parent
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
new TextSpan(
text: '4.6',
style: new TextStyle(
fontSize: 40, fontFamily: 'UbuntuRegular')),
new TextSpan(
text: ' /5',
style: TextStyle(
fontSize: 25,
color: Colors.grey[400],
fontFamily: 'UbuntuRegular')),
],
),
),
Text(
'FIFTEEN DAYS SCORE',
style: TextStyle(
color: Colors.grey[400], fontFamily: 'UbuntuMedium'),
)
],
),
)
],
),
);
}
}
class ProgressArc extends CustomPainter {
bool isBackground;
double arc;
Color progressColor;
ProgressArc(this.arc, this.progressColor, this.isBackground);
#override
void paint(Canvas canvas, Size size) {
final rect = Rect.fromLTRB(0, 0, 300, 300);
final startAngle = -math.pi;
final sweepAngle = arc != null ? arc : math.pi;
final userCenter = false;
final paint = Paint()
..strokeCap = StrokeCap.round
..color = progressColor
..style = PaintingStyle.stroke
..strokeWidth = 10;
if (!isBackground) {
paint.shader = gradient.createShader(rect);
}
canvas.drawArc(rect, startAngle, sweepAngle, userCenter, paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
}
first dispose the controller and then use super.dispose()
void dispose() { controller.dispose(); super.dispose(); }

Flutter: Remove space between widgets

By using CustomPainter i have created a half circle.Now i have this widget tree:
return Scaffold(
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
// card view
height: 100,
alignment: Alignment.center,
margin: EdgeInsets.only(
top: 20.0, bottom: 0.0, left: 50.0, right: 50.0),
decoration: BoxDecoration(
boxShadow: ([
BoxShadow(
color: color_transparent_black,
spreadRadius: 5,
blurRadius: 3.0,
offset: Offset(2, 3),
),
]),
borderRadius: BorderRadius.circular(14.0),
),),
MyArc(diameter: 200),
This is MyArc:
class MyArc extends StatelessWidget {
final double diameter;
const MyArc({Key key, this.diameter = 200}) : super(key: key);
#override
Widget build(BuildContext context) {
return CustomPaint(
painter: MyPainter(),
size: Size(diameter, diameter),
);
}
}
// This is the Painter class
class MyPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()..color = Colors.blue;
canvas.drawArc(
Rect.fromCenter(
center: Offset(size.height / 2, 0),
height: size.height,
width: size.width,
),
6.4,
2.9,
false,
paint,
);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
But i got this problem:
I don't want any space between gray and blue shape!!!
I finally figured it out...
import 'dart:math' as math;
//...
class MyPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint blue = Paint()..color = Colors.blue;
canvas.translate(0, -size.height / 2);
canvas.drawArc(
Offset.zero & size,
-math.pi,
-math.pi,
false,
blue,
);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
If you want to make your canvas fit nicely also you can make it rectangular like so...
CustomPaint(
painter: MyPainter(),
size: Size(diamieter, diameter / 2),
)
Then have you custom painter as...
class MyPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint blue = Paint()..color = Colors.blue;
Paint red = Paint()..color = Colors.red;
canvas.drawRect(Offset.zero & size, red);
canvas.translate(0, -size.height);
canvas.drawArc(
Offset.zero & Size(size.width, size.height * 2),
-math.pi,
-math.pi,
false,
blue,
);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
It'll fit snug this way...
try changing the spreadRadius to 3.0
Its possible that it's creating a boundary greater than the container's Blur Radius boundary.
BoxShadow(
color: color_transparent_black,
spreadRadius: 5,
blurRadius: 3.0,
offset: Offset(2, 3),
),

Flutter : Need help to implement card with image

I need to implement a design similar to the image displayed below:
Here is a possible solution with a CustomPainter and a Path to generate the drawing. I used the cubicTo and a addRect functions of the Path class. For more information about these functions and path drawing, I refer to this: Paths in Flutter: A Visual Guide
This is the class which extends the CustomPainter
class CardPainter extends CustomPainter {
final Color color;
final double strokeWidth;
CardPainter({this.color = Colors.black, this.strokeWidth = 3});
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = color
..strokeWidth = this.strokeWidth
..style = PaintingStyle.stroke;
canvas.drawPath(getShapePath(size.width, size.height), paint);
}
// This is the path of the shape we want to draw
Path getShapePath(double x, double y) {
return Path()
..moveTo(2 * x / 3, y)
..cubicTo(x / 1.5, y, 0, y / 3, x, 0) // draw cubic curve
..addRect(Rect.fromLTRB(0, 0, x, y)); // draw rectangle
}
#override
bool shouldRepaint(CardPainter oldDelegate) {
return oldDelegate.color != color;
}
}
Here is the implementation of the CustomPainter
class CustomCard extends StatelessWidget {
CustomCard({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Card Demo')),
body: Center(
child: Container(
color: Colors.grey[300],
width: 250,
height: 120,
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: CustomPaint(
painter: CardPainter(color: Colors.blueAccent, strokeWidth: 3), // this is your custom painter
child: Stack(
children: <Widget>[
Positioned(
top: 25,
left: 30,
child: Text('Text1'),
),
Positioned(
top: 55,
left: 150,
child: Text('Text2'),
),
],
),
),
),
),
);
}
}