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.
Related
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'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;
}
Could you suggest my how to implement BottomAppBar with shape as you could see in picture bellow
I'm trying to wrap BottomAppBar with ClipRRect
return ClipRRect(
borderRadius: BorderRadius.vertical(
top: Radius.circular(40),
),
child: BottomAppBar(
key: widget.key,
shape: widget.notchedShape,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: items,
),
color: Colors.red, //widget.backgroundColor,
),
);
But result is not as I wish
You can use CustomPainter() and using that you can make your own design.
This is not perfect as you have shown by you but you can always tweak the setting on your own.
class MyCustomPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint_0 = new Paint()
..color = Colors.white
..style = PaintingStyle.fill;
Path path_0 = Path();
path_0.moveTo(size.width * 0.0500000, size.height * 0.9000000);
path_0.cubicTo(
size.width * 0.5000000,
size.height * 0.8400000,
size.width * 0.4975000,
size.height * 0.8380000,
size.width * 0.9500000,
size.height * 0.9000000);
path_0.quadraticBezierTo(
size.width * 1, size.height * 0.9, size.width, size.height);
path_0.lineTo(0, size.height);
path_0.quadraticBezierTo(size.width * 0, size.height * 0.90,
size.width * 0.0500000, size.height * 0.9000000);
path_0.close();
canvas.drawPath(path_0, paint_0);
canvas.drawShadow(path_0, Color(0x68FFFFFF), 8, true);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
Output
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')),
),
)