How can I fix my problem with clippath flutter? - flutter

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

Related

How do I shape an image as i desire in flutter

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
)

Flutter : How to get a straight line using CustomClippers

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()),
),

Flutter reverse clipper direction

I need to show triangle type shape container which is almost complete but there is one issue its showing the triangle shape in opposite direction my code
class ClipPathClass extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var roundnessFactor = 50.0;
var path = Path();
path.moveTo(0, size.height * 0.33);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(
size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, roundnessFactor * 2);
path.quadraticBezierTo(size.width - 10, roundnessFactor,
size.width - roundnessFactor * 1.5, roundnessFactor * 1.5);
path.lineTo(
roundnessFactor * 0.6, size.height * 0.33 - roundnessFactor * 0.3);
path.quadraticBezierTo(
0, size.height * 0.33, 0, size.height * 0.33 + roundnessFactor);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
This is how i am showing this
ClipPath(
clipper: RoundedDiagonalPathClipper(),
child: Container(
height: 320,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.0)),
color: Colors.orange,
),
child: null,
),
),
Out put is showing like this
But i need to show the upper part like this just reverse it. I play with everything but it's not reversing.
I implemented _getY function so that there is no bend in the corner. And I added an equalization variable to make look better.
Reference: Paths in Flutter: A Visual Guide.
Screenshot
RoundedDiagonalPathClipper.dart
class RoundedDiagonalPathClipper extends CustomClipper<Path> {
double _getY(double x) {
return x * 0.33;
}
#override
Path getClip(Size size) {
var roundnessFactor = 50.0;
var equalization = 10.0;
var path = Path();
path.moveTo(0, roundnessFactor);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(
size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, _getY(size.width) + roundnessFactor - equalization);
path.quadraticBezierTo(
size.width,
_getY(size.width),
size.width - roundnessFactor + equalization,
_getY(size.width - roundnessFactor + equalization));
path.lineTo(
roundnessFactor + equalization, _getY(roundnessFactor + equalization));
path.quadraticBezierTo(0, 0, 0, roundnessFactor + equalization);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
Edit: Adding shadow
I made the shadow version by using the gist:coman3-ClipShadowPath.dart.
ClipShadowPath.dart
#immutable
class ClipShadowPath extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Path> clipper;
final Widget child;
ClipShadowPath({
required this.shadow,
required this.clipper,
required this.child,
});
#override
Widget build(BuildContext context) {
return CustomPaint(
key: UniqueKey(),
painter: _ClipShadowShadowPainter(
clipper: this.clipper,
shadow: this.shadow,
),
child: ClipPath(child: child, clipper: this.clipper),
);
}
}
class _ClipShadowShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Path> clipper;
_ClipShadowShadowPainter({required this.shadow, required this.clipper});
#override
void paint(Canvas canvas, Size size) {
var paint = shadow.toPaint();
var clipPath = clipper.getClip(size).shift(shadow.offset);
canvas.drawPath(clipPath, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Usage
ClipShadowPath(
shadow: Shadow(blurRadius: 20.0, color: Colors.black54),
clipper: RoundedDiagonalPathClipper(),
child: Container(color: Colors.orange),
)
just apply Matrix transformation on Path, so you will free to do any changes on path, it will flip vertically any path
how to use:
clipper: ClipPathClass(),
or if need to reverse
clipper: ClipPathClass(flip: true),
class ClipPathClass extends CustomClipper<Path> {
final roundnessFactor = 50.0;
final bool flip;
ClipPathClass({this.flip = false});
#override
Path getClip(Size size) {
final path = Path();
path.moveTo(0, size.height * 0.33);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, roundnessFactor * 2);
path.quadraticBezierTo(size.width - 10, roundnessFactor, size.width - roundnessFactor * 1.5, roundnessFactor * 1.5);
path.lineTo(roundnessFactor * 0.6, size.height * 0.33 - roundnessFactor * 0.3);
path.quadraticBezierTo(0, size.height * 0.33, 0, size.height * 0.33 + roundnessFactor);
return flip ? _flip(path, size.width) : path;
}
Path _flip(Path path, double width) {
final m = Matrix4.identity()
..translate(width)
..rotateY(math.pi);
return path.transform(m.storage);
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
I won't explain the change line by line, I tried to keep the round corner uniform on the four corners.
Here your are:
class RoundedDiagonalPathClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var roundnessFactor = 50.0;
var path = Path();
path.moveTo(0, roundnessFactor);
path.lineTo(0, size.height - roundnessFactor);
path.quadraticBezierTo(0, size.height, roundnessFactor, size.height);
path.lineTo(size.width - roundnessFactor, size.height);
path.quadraticBezierTo(
size.width, size.height, size.width, size.height - roundnessFactor);
path.lineTo(size.width, size.height * 0.33 + roundnessFactor * 0.5);
path.quadraticBezierTo(
size.width,
size.height * 0.33,
size.width - roundnessFactor,
size.height * 0.33 - roundnessFactor * 0.5);
path.lineTo(roundnessFactor, 0);
path.quadraticBezierTo(0, 0, 0, roundnessFactor);
return path;
}
The result will be this one:

Perspective on overlay clippath in Flutter

I would like to operate some perspective on a ClipPath overlay with Flutter.
I reproduced inverted Clip Oval from Flutter: inverted ClipOval which works fine.
Then i would like to operate a perspective on this overlay:
For now i use a Transform widget but the "grey background" gets also rotated.I would like the background to expand on all screen left.
I think i should rotate only in InvertedRectClipper but i can't find a way to do something similar as alignment: FractionalOffset.center which tell where is the origin to rotate on.
Anyone have a tips for this ?
Actual screenshot :
Background is not entirely grey
Full code to test :
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: SafeArea(
child: Stack(
children: <Widget>[
Container(
color: Colors.white,
),
Transform(
alignment: FractionalOffset.center,
transform: Matrix4.identity()
..setEntry(3, 2, 0.0005) // perspective
..rotateX(-0.9),
child: ClipPath(
clipper: InvertedRectClipper(),
child: Container(
color: Color.fromRGBO(0, 0, 0, 0.5),
),
),
)
],
),
),
));
}
class InvertedRectClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
return Path()
..addRect(Rect.fromCenter(
center: Offset(size.width / 2, size.height / 2),
width: size.width / 2,
height: size.height / 2))
..addRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height))
..fillType = PathFillType.evenOdd;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
The key is to only transform the path you need to transform, not the whole widget.
Here is a sample :
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: SafeArea(
child: Stack(
children: <Widget>[
Container(
color: Colors.blue,
),
ClipPath(
clipper: InvertedRectClipper(),
child: Container(
color: Colors.black.withOpacity(0.5),
),
)
],
),
),
));
}
class InvertedRectClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
// First rectangle, to be transformed
var path = Path()
..fillType = PathFillType.evenOdd
..addRect(Rect.fromCenter(
center: Offset(size.width / 2, size.height / 2),
width: size.width / 2,
height: size.height / 2));
// Transform matrix
final matrix = Matrix4.identity()
..setEntry(3, 2, 0.0005)
..rotateX(-0.9);
path = path.transform(matrix.storage);
// Outer rectangle, straight
path.addRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height));
// Return path
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
Here is the result
You'll 'just' have to adapt the transformation to your convenance.
** EDIT **
If you need the transformation to be centered relative to your rectangle, an easy way is to draw the rectangle centered on the origin, apply the transformation, then translate it to be centered to the screen :
Path getClip(Size size) {
// First rectangle, to be transformed, centered at the origin
var path = Path()
..fillType = PathFillType.evenOdd
..addRect(Rect.fromCenter(
center: Offset(0, 0),
width: size.width / 2,
height: size.height / 2));
// Rotation X
final matrix = Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(-0.9);
path = path.transform(matrix.storage);
// Translation to center back the rectangle
path = path.transform(Matrix4.translationValues(size.width / 2, size.height / 2, 0).storage);
// Outer rectangle, straight
path.addRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height));
// Return path
return path;
}

Flutter Dart - How to make a container with outward borderRadius.circular(20) instead of inward?

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.