How to design tile like given image? - flutter

I'm trying to making tile like below image.
This is the piece of code that I have tried:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ListTile(
leading: Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height/20,
width: MediaQuery.of(context).size.height/20,
decoration: BoxDecoration(
color: index.isEven?Colors.yellow:Colors.orange,
shape: BoxShape.circle,
image: snapshot.data.content[index].image != null? DecorationImage(
image: NetworkImage(snapshot.data.content[index].image.fileUrl),
fit: BoxFit.cover
):null
),
child: snapshot.data.content[index].image == null?
Icon(Icons.person):Container()
),
title:Text(
snapshot.data.content[index].name, style: TextStyle(
fontWeight: FontWeight.bold)
),
subtitle: Text(snapshot.data.content[index].phoneNumber),
trailing: Container(
alignment: Alignment.centerRight,
width: MediaQuery.of(context).size.width/5.5,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset('assets/icons/reminder.png',fit: BoxFit.cover,
),
Image.asset('assets/icons/calendar_soon.png',fit: BoxFit.cover,),
],
),
),
onTap: (){
//
},
),
Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height/25,
width: MediaQuery.of(context).size.width/1.5,
decoration: BoxDecoration(
color: Colors.green[100],
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
topLeft: Radius.circular(10),
bottomRight: Radius.circular(30),
)
),
child: Text("12 Mar, Marriage Anniversary",style:TextStyle(color: Colors.green)),
),
SizedBox(height:5),
Divider(height: 0.5,)
],
)
and What I have got from this code:

This is my attempt using a CustomPainter:
class CurvePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final radius = 16.0;
final tipHeight = size.height * 0.2;
final paint = Paint()..color = const Color(0xFFDEF8EB);
final path = Path()
..moveTo(0, tipHeight)
..lineTo(0, size.height - radius)
..quadraticBezierTo(0, size.height, radius, size.height)
..lineTo(size.width - radius, size.height)
..quadraticBezierTo(
size.width, size.height, size.width, size.height - radius)
..lineTo(size.width, tipHeight + radius)
..quadraticBezierTo(size.width, 0, size.width - radius, 0)
..quadraticBezierTo(size.width - radius, tipHeight,
size.width - (radius + 8.0), tipHeight)
..lineTo(radius, tipHeight)
..quadraticBezierTo(0, tipHeight, 0, tipHeight + radius);
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
To implement it, you need to use the CustomPaint widget:
Container(
height: 50.0,
width: 300,
child: CustomPaint(
painter: CurvePainter(),
),
),

Related

How to create a button like this in flutter?

I have wrote this much code. I am trying to use custom painter here to draw those lines. But I don't know how to fill cooler inside them. I am using row to divide these 3 sections. But I am not sure if this is the right way.
Container(
height: 10.0.h,
padding: EdgeInsets.only(left: 20),
color: Color.fromRGBO(211, 237, 241, 1),
child: Row(
children: [
Container(
width: 70.0.w,
child: Text(
"Create an Event",
textAlign: TextAlign.left,
style: TextStyle(fontSize: 22.0.sp),
),
),
Flexible(
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.blue,
child: CustomPaint(
painter: CurvedPainter(),
),
),
)
],
),
)
class CurvedPainter extends CustomPainter { #override void paint(Canvas canvas, Size size) {
print(size.width);
print(size.height);
var paint = Paint();
var path = Path();
paint.color = Colors.red;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 2.0;
path.arcToPoint(Offset(-20, size.height * 0.5),
radius: Radius.circular(100), clockwise: false);
path.arcToPoint(Offset(-30, size.height),
radius: Radius.circular(70), clockwise: true);
canvas.drawPath(path, paint); }
}
I have made this with custom painter you can edit the values to customize the shape
Add this as a body of your Widget
Container(
height: 50,
width: 250,
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.all(Radius.circular(20))),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(20)),
child: Row(
children: [
Expanded(
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
height: 50,
color: Colors.blue.shade50,
child: Text('Hello'),
),
),
Container(
width: 70,
height: 50,
child: Stack(
children: [
Container(
width: 70,
height: 50,
child: CustomPaint(
painter: buttonBackground(),
),
),
Align(
alignment: Alignment(.8,1),
child: IconButton(icon: Icon(Icons.arrow_forward_ios_rounded), onPressed: (){})),
],
),
),
],
),
),
),
And you can change the value and color of the button background in this class
class buttonBackground extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
var sw = size.width;
var sh = size.height;
var paint = Paint();
Path mainBackground = Path();
mainBackground.addRect(Rect.fromLTRB(0, 0, sw, sh));
paint.color = Colors.blue.shade50;
canvas.drawPath(mainBackground, paint);
Path greyWave = Path();
greyWave.lineTo(sw, 0);
greyWave.lineTo(sw, sh);
greyWave.cubicTo(sw * 0.15, sh, sw * 0.5, sh, sw * .6, sh * 0.5);
greyWave.cubicTo(sw * 0.92, sh * 01.2, 0, sh * 0.15, sh * .4, sh * 0);
greyWave.close();
paint.color = Colors.blue.shade200;
canvas.drawPath(greyWave, paint);
Path blueWave2 = Path();
greyWave.lineTo(sw, 0);
greyWave.lineTo(sw, sh);
greyWave.cubicTo(sw * 0.05, sh, sw * 0.3, sh, sw * .4, sh * 0.5);
greyWave.cubicTo(sw * 0.62, sh * 0.92, 0, sh * 0.15, sh * .3, sh * 0);
greyWave.close();
paint.color = Colors.blue.withOpacity(.3);
canvas.drawPath(greyWave, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return oldDelegate != this;
}
}
I don't have access right now in an IDE to write flutter code. But I guess you can use a GestureDetector where inside of it you can add the button functionality in the onTap argument and as a child you can use the Image that you have created and want to use for the button.
Something like this below:
GestureDetector(
onTap: () {print('put a method here that runs the code that you want to be executed on tap');},
child: Image(
image: AssetImage('path/to/your/img'),
fit: BoxFit.cover,
height: 30,
),
)

How to create stacked wave containers

I want to implement this screen with this waves and with the same curves , I'm trying to put multi containers in stack to get this shape but I can't , the top part of screen will be slider of images
and this is my code which I used to draw this screen
Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
gradient: LinearGradient(
end: Alignment.centerRight,
begin: Alignment.centerLeft,
colors: [
blueColor,
lightColor,
],
),
),
child: Stack(
alignment: Alignment.topCenter,
children: [
Container(
height: MediaQuery.of(context).size.height * .5,
decoration: BoxDecoration(),
child: Stack(
children: [
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * .5,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(100),
),
image: DecorationImage(
image: AssetImage('assets/images/bg.png'),
fit: BoxFit.cover)),
),
Positioned(
bottom: 0,
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * .08,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(150),
topLeft: Radius.circular(150),
),
gradient: LinearGradient(
end: Alignment.centerRight,
begin: Alignment.centerLeft,
colors: [
blueColor,
lightColor,
],
),
),
),
),
],
),
),
Positioned(
bottom: 0,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
end: Alignment.centerRight,
begin: Alignment.centerLeft,
colors: [
blueColor,
lightColor,
],
),
),
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * .5,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(120),
),
color: Colors.white),
),
),
),
],
),
),
);
but this is the result which I have and have no idea to complete it
So can anyone help me in my case please !
You can make this with a CustomPainter, here is how you could do it and how it looks.
class StackedWaves extends StatelessWidget {
const StackedWaves({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: StackedWavesPainter(),
);
}
}
class StackedWavesPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..shader = LinearGradient(colors: [
Colors.green,
Colors.lightGreenAccent,
]).createShader(Offset.zero & size);
final double side = 80;
final double radius = 80;
final path = Path()
..moveTo(0, size.height / 2 + side)
..arcToPoint(Offset(side, size.height / 2),
radius: Radius.circular(radius))
..lineTo(size.width - side, size.height / 2)
..arcToPoint(Offset(size.width, size.height / 2 - side),
radius: Radius.circular(radius), clockwise: false)
..lineTo(size.width, size.height)
..lineTo(0, size.height)
..close();
canvas.save();
canvas.drawPath(path, paint);
canvas.restore();
canvas.save();
canvas.translate(0, 100);
canvas.drawPath(path, Paint()..color = Colors.white);
canvas.restore();
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
Of course you can play with the variables "side" and "radius" if you want, just make sure they do not have a difference greater than 20 or so, I've seen if you change it like that you might not get the result you want.

How to subtract one container from another?

I am new to Flutter. I was trying to implement this UI 👇👇
The way I was implementing is
class SearchFlightBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
left: 25,
right: 25,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RoundButton(
icon: Arrow_Forward.icon_ionic_md_arrow_round_back,
title: "ONE WAY",
iconSize: 10,
),
RoundButton(
icon: Two_Arrows.group_73,
title: "ROUND TRIP",
iconSize: 16,
),
],
),
Container(
// base Conatiner
margin: EdgeInsets.only(
top: 35,
),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
offset: Offset(-10, -10),
blurRadius: 15,
color: Color(0xffFFFFFF)),
],
borderRadius: BorderRadius.circular(4),
color: Color(0xffF6F9FF),
),
child: ClipPath(
clipper: MyCustomClipper(),
child: Container(
//Subtraction Container
decoration: BoxDecoration(
// color: Color(0xffF6F9FF),
color: Colors.red,
border: Border.all(
color: Color(0x00000000),
),
boxShadow: [
BoxShadow(
offset: Offset(0, 5),
blurRadius: 10,
color: Color(0x0f140B2B),
),
]),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: 15,
),
child: Icon(
TakeOff.take_off,
size: 30,
color: Theme.of(context).accentColor,
),
),
Padding(
padding: const EdgeInsets.only(
top: 15,
bottom: 5,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'FORM',
style: Theme.of(context).textTheme.caption,
),
SizedBox(
height: 10,
),
Text(
'Sydney, Austraila',
),
],
),
)
],
),
),
),
),
// Container(
// margin: EdgeInsets.only(
// right: 25,
// ),
// transform: Matrix4.translationValues(-3.0, -20, 0.0),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(50),
// color: Colors.red,
// ),
// height: 50,
// width: 50,
// ),
// Container(
// height: 100,
// width: double.infinity,
// color: Colors.red,
// )
],
),
);
}
}
My Custom Clipper is
import 'dart:math';
import 'package:flutter/cupertino.dart';
class MyCustomClipper extends CustomClipper<Path> {
#override
getClip(Size size) {
Size newSize = Size(size.width, size.height - 40);
double radius = 40;
Offset center = Offset(6 * size.width / 7, size.height + 20);
Offset firstEnd = Offset(6 * size.width / 7, size.height - radius);
Offset secondEnd = Offset(6 * size.width / 7 + radius, size.height);
print('size: ' + size.toString());
// TODO: implement getClip
Path path = Path()
// ..lineTo(0, size.height)
// ..lineTo(0, size.height)
// ..arcToPoint(
// Offset(7 * size.width / 8, size.height - radius),
// radius: Radius.circular(radius),
// )
// ..arcToPoint(
// Offset(7 * size.width / 8 + radius, size.height),
// radius: Radius.circular(radius),
// )
// // ..arcTo(
// // Rect.fromCircle(
// // center: Offset(3 * size.width / 4, size.height),
// // radius: radius,
// // ),
// // 1 * pi,
// // 2,
// // true)
// ..lineTo(size.width, size.height)
..arcTo(
Rect.fromCircle(
center: center,
radius: radius,
),
1.3 * pi,
1.8 * pi,
true);
// ..lineTo(size.width, 0)
// ..lineTo(0, 0)
return path;
}
#override
bool shouldReclip(covariant CustomClipper oldClipper) {
// TODO: implement shouldReclip
return false;
}
}
As You can see, I was first clipping with ..artoPoint(). But That was just joining the two point with arc radius. That function is cutting a semicircle.
And I tried with ..arTo() function. But In that Function, I have to specify the start angle and sweep angle. But There is no way I can tell the value of both angle(Is there any way to know?).
I just want a function that will just draw a circle at a given center. And Just cut the portion of the container(in my case) and be done with it.
Or is There anyway I can do?

Invisible part of container

I try to make invisible part of container, a circle that is cut out of it.
That's my goal: https://www.autodraw.com/share/FU2LW3XS7H18
This is my container:
Container(
color: Colors.white,
height: size.height/2 - size.width/2,
width: size.width,
);
And the circle that I want to cut out:
child: GestureDetector(
child: Container(
child: Opacity(opacity: 1),
width: 50,
height: 50,
decoration: ShapeDecoration(
shape: new CircleBorder(
side: new BorderSide(
width: 10.0, color: Colors.black)))))
And this is what I tried but didn't work:
Container(
color: Colors.white,
height: size.height/2 - size.width/2,
width: size.width,
child: Opacity(opacity: 1, child: GestureDetector(
child: Container(
width: 50,
height: 50,
decoration: ShapeDecoration(
shape: new CircleBorder(
side: new BorderSide(
width: 10.0, color: Colors.black)))))),
);
You can use CustomClipper to achieve this look. fillType = PathFillType.evenOdd is required.
class InvertedClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
return Path()
..addRect(Rect.fromLTWH(0, 0, size.width, size.height))
..addOval(Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2),
radius: 50))
..fillType = PathFillType.evenOdd;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
You will need to adjust values for your needs.
Please note that this will not work on web. This is a known bug reported here.
In the widget tree use ClipPath to use InvertedClipper. Here's implementation:
ClipPath(
clipper: InvertedClipper(),
child: Container(
color: Colors.red,
height: 200
),
),
Source: https://stackoverflow.com/a/49396544/7616528

How can I create a Half Circle without Spacing in Flutter [duplicate]

This question already has answers here:
Flutter how to draw semicircle (half circle)
(6 answers)
Closed 3 years ago.
I want to create a half Circle at the bottom. But theres some space which I cant delete.
// Flutter
Image:
#override
Path getClip(Size size) {
final Path path = new Path();
path.lineTo(0.0, size.height / 2);
path.lineTo(size.width, size.height / 2);
path.lineTo(size.width, 0);
return path;
}
why not going the easy way
something like this
Container(
height: 30,
width: 50,
color: Colors.transparent,
child: new Container(
decoration: new BoxDecoration(
color: Colors.black,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(40.0),
topRight: const Radius.circular(40.0),
),
),
),
),
You can easily achieve this view using ArcView link. See attached image
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Row(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Arc(
arcType: ArcType.CONVEX,
edge: Edge.TOP,
height: 70.0,
clipShadows: [ClipShadow(color: Colors.black)],
child: new Container(
height: 70,
width: MediaQuery.of(context).size.width,
color: Colors.lime,
),
),
),
],
),
),
);
}
Or create a custom clipper
class CustomHalfCircleClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
final Path path = new Path();
path.lineTo(0.0, size.height / 2);
path.lineTo(size.width, size.height / 2);
path.lineTo(size.width, 0);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return true;
}
}
Use Above class as shown below
new ClipPath(
clipper: new CustomHalfCircleClipper(),
child: new Container(
height: MediaQuery.of(context).size.width,
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(
MediaQuery.of(context).size.width / 2),
),
),
)