Flutter: CurveClipper with Container - flutter

I'm trying to curve a container using this code:
class CurveClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
int curveHeight = 40;
Offset controlPoint = Offset(size.width / 2, size.height + curveHeight);
Offset endPoint = Offset(size.width, size.height - curveHeight);
Path path = Path()
..lineTo(0, size.height - curveHeight)
..quadraticBezierTo(controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy)
..lineTo(size.width, 0)
..close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
Usage:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// The title text which will be shown on the action bar
title: Text(title),
),
body: Container(
child: ClipPath(
clipper: CurveClipper(),
child: Container(
color: Colors.red,
height: 200.0,
),
),
),
);
}
However, this gets me this:
Screenshot
But I want the curve to be at the top of the container, not the bottom. How can I achieve this?

This one work for me
ClipPath File
Container(
margin: EdgeInsets.only(left: 15, right: 15),
alignment: Alignment.center,
child: ClipPath(
clipper: ClipPathClass(),
child: SizedBox(
width: 320,
height: 240,
child: Container(
color: Colors.red,
),
),
),
),
ClipPathClass File
class ClipPathClass extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = Path();
path.moveTo(0.0, size.height - (size.height * 6 / 8));
var secondControlPoint = Offset(size.width / 2, 0);
var secondPoint = Offset(size.width, size.height - (size.height * 6 / 8));
path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy,
secondPoint.dx, secondPoint.dy);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}

Related

how can I make may Image be like this shape?

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.

Draw Bezier curve with rectangle in Flutter

I'm starting with Flutter and have to design a UI that looks like
But with icon button at the center of the Bezier curve.
What I tried is
class HeaderPainter extends CustomPainter {
HeaderPainter({
#required this.color,
#required this.avatarRadius
});
final Color color;
final double avatarRadius;
#override
void paint(Canvas canvas, Size size) {
final shapeBounds = Rect.fromLTRB(0, 0, size.width, size.height - avatarRadius);
final centerAvatar = Offset(shapeBounds.center.dx, shapeBounds.bottom);
final avatarBounds = Rect.fromCircle(center: centerAvatar, radius: avatarRadius).inflate(3);
_drawBackground(canvas, shapeBounds, avatarBounds);
}
#override
bool shouldRepaint(HeaderPainter oldDelegate) {
return color != oldDelegate.color;
}
void _drawBackground(Canvas canvas, Rect shapeBounds, Rect avatarBounds) {
final paint = Paint()..color = color;
final backgroundPath = Path()
..moveTo(shapeBounds.left, shapeBounds.top)
..lineTo(shapeBounds.bottomLeft.dx, shapeBounds.bottomLeft.dy)
..arcTo(avatarBounds, -pi, pi, false)
..lineTo(shapeBounds.bottomRight.dx, shapeBounds.bottomRight.dy)
..lineTo(shapeBounds.topRight.dx, shapeBounds.topRight.dy)
..lineTo(0.0, shapeBounds.height - 100)
..quadraticBezierTo(
shapeBounds.width / 4, shapeBounds.height,
shapeBounds.width / 2, shapeBounds.height
)
..quadraticBezierTo(
shapeBounds.width - shapeBounds.width / 4, shapeBounds.height,
shapeBounds.width, shapeBounds.height - 100
)
..lineTo(shapeBounds.width, 0.0)
..close();
canvas.drawPath(backgroundPath, paint);
}
}
And the outcome is
How can I get the bezier curve with the rectangle?
Edit 2: The HeaderPainter is used like
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
child: CustomPaint(
size: Size.fromHeight(400.0),
painter: HeaderPainter(
color: Colors.red,
avatarRadius: avatarRadius
),
),
),
Positioned(
left: 0,
right: 0,
bottom: titleBottomMargin,
child: Column(
children: <Widget>[
Text('Hello World', style: TextStyle(fontWeight: FontWeight.bold),),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: CircleAvatar(
radius: avatarRadius,
backgroundColor: Colors.green,
child: IconButton(icon: Icon(Icons.message), onPressed: _onAddMessageButtonClick,),
),
)
],
);
}
Got it solved using ClipPath and CustomClipper.
The updated build() method is
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
child: ClipPath(
clipper: HeaderClipper(avatarRadius: avatarRadius),
child: CustomPaint(
size: Size.fromHeight(400.0),
painter: HeaderPainter(
color: Colors.green,
avatarRadius: avatarRadius
),
),
),
),
...
and HeaderClipper
class HeaderClipper extends CustomClipper<Path> {
HeaderClipper({
#required this.avatarRadius
});
final avatarRadius;
#override
getClip(Size size) {
final path = Path()
..lineTo(0.0, size.height - 100)
..quadraticBezierTo(
size.width / 4, (size.height - avatarRadius),
size.width / 2, (size.height - avatarRadius)
)
..quadraticBezierTo(
size.width - (size.width / 4), (size.height - avatarRadius),
size.width, size.height - 100
)
..lineTo(size.width, 0.0)
..close();
return path;
}
#override
bool shouldReclip(CustomClipper oldClipper) {
return false;
}
}
The final output is

Facing issue in making this in flutter

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

Flutter : Achieved Sliverappbar Shape

I'm found some Appbar design in Dribble https://dribbble.com/shots/9175650-Beauty-Salon-App/attachments/1218583?mode=media , I try to create same like that but i confused get border radius each other side.
Trial 1 Without Background :
Trial 2 With Scaffold Background Color Blue
Trial 3 With background Color Deep Orange
How can i achieved appbar design like the link ?
Source Code
import 'package:flutter/material.dart';
import 'package:flutter_iconpicker/flutter_iconpicker.dart';
class TestingScreen extends StatelessWidget {
static const routeName = "/testing-screen";
#override
Widget build(BuildContext context) {
var mediaQuery = MediaQuery.of(context);
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
expandedHeight: mediaQuery.size.height / 4,
backgroundColor: Colors.deepOrange,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.only(bottomRight: Radius.circular(80))),
),
SliverList(
delegate: SliverChildListDelegate(
[
Container(
height: mediaQuery.size.height,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius:
BorderRadius.only(topLeft: Radius.circular(80))),
child: Center(child: Text('data')),
)
],
),
)
],
),
);
}
}
You can actually use CustomClipper to do this, with a method of Path quadraticBezierTo:
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Stack(
children: <Widget>[
Container(color: Colors.orange),
ClipPath(
clipper: TheCustomClipper(),
child: Container(
color: Colors.greenAccent,
),
),
],
),
),
);
}
}
class TheCustomClipper extends CustomClipper<Path> {
#override
getClip(Size size) {
var path = Path();
path.lineTo(0, size.height / 3);
var firstControlPoint = Offset(0, size.height / 3.5); // adjust the height to move start of the first curve
var firstEndPoint = Offset(size.width / 4.2, size.height / 3.5 + 10); // adjust the width to add the end controll point and height to move end of the first curve
var secControlPoint = Offset(size.width, size.height / 2.8); // adjust the height to move end of the second curve
var secEndPoint = Offset(size.width, size.height / 3 - 40); // adjust the width to add the right first controll point and height to move start of the second curve
path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
firstEndPoint.dx, firstEndPoint.dy);
path.quadraticBezierTo(
secControlPoint.dx, secControlPoint.dy, secEndPoint.dx, secEndPoint.dy);
path.lineTo(size.width, size.height / 3);
path.lineTo(size.width, 0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper oldClipper) {
return null;
}
}
Do note that, I only added curve to first widget. If you want to add another CustomClipper to the first Container of the Stack, do it by doing the reverse of the logic.
Output:
Source Code:
import 'package:flutter/material.dart';
import '../../../shared/app_colors.dart';
class WelcomenPage extends StatelessWidget {
static const id = 'welcomen_page';
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
ClipPath(
child: Container(
height: MediaQuery.of(context).size.height,
color: AppColors.primary,
),
clipper: BottomWaveClipper(),
),
],
),
);
}
}
class BottomWaveClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, size.height * .65);
var firstControlPoint = Offset(0, size.height * .75);
var firstEndPoint = Offset(size.width / 6, size.height * .75);
path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
firstEndPoint.dx, firstEndPoint.dy);
path.lineTo(size.width / 1.2, size.height * .75);
var secControlPoint = Offset(size.width, size.height * .75);
var secEndPoint = Offset(size.width, size.height * 0.85);
path.quadraticBezierTo(
secControlPoint.dx, secControlPoint.dy, secEndPoint.dx, secEndPoint.dy);
path.lineTo(size.width, 0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
Output:
image

Flutter Cards : How can i create a custom card widget in flutter

I am trying to create a custom card in flutter that looks like this :
how can i achieve this in flutter ?
This is what i want to achieve:
You could use ClipPath for custom clipping your widget
ClipPath(clipper: _CustomClipper(), child: Container(width: 200.0, height: 100.0, color: Colors.grey,),)
(gray container just for example)
const double _topPadding = 20.0;
const double _arcRadius = 8.0;
class _CustomClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
double point = size.width / 3 * 2;
final path = Path()
..moveTo(0.0, _topPadding)
..lineTo(point, _topPadding)
..lineTo(point, _arcRadius)
..lineTo(point + _arcRadius, 0.0)
..lineTo(size.width - _arcRadius, 0.0)
..lineTo(size.width, _arcRadius)
..lineTo(size.width, size.height)
..lineTo(0.0, size.height)
..lineTo(0.0, _topPadding)
..addOval(Rect.fromLTRB(
point, 0.0, point + 2 * _arcRadius, 2 * _arcRadius))
..addOval(Rect.fromLTRB(
size.width - 2 * _arcRadius, 0.0, size.width, 2 * _arcRadius));
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
UPD - elevated solution
Material(
color: Colors.yellow,
clipBehavior: Clip.antiAlias,
shape: _CustomBorder(),
elevation: 16.0, child: Container(width: 200.0, height: 100.0, child: Stack(
children: <Widget>[
Positioned(child: FittedBox(fit: BoxFit.scaleDown, child: Text('and a text here too'),),left: 140.0, right: 4.0, top: 4.0,),
Positioned(child: Text('I want a text here', style: TextStyle(fontSize: 24.0),), top: 40.0, left: 4.0,)
],
),),)
...
class _CustomBorder extends BorderDirectional {
#override
Path getOuterPath(ui.Rect rect, {ui.TextDirection textDirection}) {
Size size = rect.size;
double point = size.width / 3 * 2;
final path = Path()
..moveTo(0.0, _topPadding)
..lineTo(point, _topPadding)
..lineTo(point, _arcRadius)
..lineTo(point + _arcRadius, 0.0)
..lineTo(size.width - _arcRadius, 0.0)
..lineTo(size.width, _arcRadius)
..lineTo(size.width, size.height)
..lineTo(0.0, size.height)
..lineTo(0.0, _topPadding)
..addOval(Rect.fromLTRB(
point, 0.0, point + 2 * _arcRadius, 2 * _arcRadius))
..addOval(Rect.fromLTRB(
size.width - 2 * _arcRadius, 0.0, size.width, 2 * _arcRadius));
path.close();
return path;
}
}
import 'package:getwidget/getwidget.dart';
GFCard(
boxFit: BoxFit.cover,
image: Image.asset('your asset image'),
title: GFListTile(
avatar: GFAvatar(
backgroundImage: AssetImage('your asset image'),
),
title: Text('Card Title'),
subTitle: Text('Card Sub Title'),
),
content: Text("Some quick example text to build on the card"),
buttonBar: GFButtonBar(
children: <Widget>[
GFButton(
onPressed: () {},
text: 'Buy',
),
GFButton(
onPressed: () {},
text: 'Cancel',
),
],
),
),
Read complete article for Flutter card - https://docs.getwidget.dev/gf-card/