I need your help and assistance to how to implement the curved tab as shown in below picture .
This can easily be achieved by custompainter or customclipper. here is an example. I believe you can improve it to better.
Widget for bottom navbar:
Positioned(
bottom: 0,
child: Container(
height: 100,
width: MediaQuery.of(context).size.width,
color: Colors.amber,
child: Stack(children: [
AnimatedPositioned(
curve: Curves.bounceOut,
duration: const Duration(milliseconds: 300),
top: 10,
left: (MediaQuery.of(context).size.width / 3) * tab,
child: SizedBox(
width: MediaQuery.of(context).size.width / 3,
height: 50,
child: CustomPaint(
size: Size(MediaQuery.of(context).size.width / 3, 50),
painter: TabPainter(),
),
),
),
Positioned(
top: 59,
child: Container(
height: 2,
width: MediaQuery.of(context).size.width,
color: Colors.white,
),
),
Positioned(
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: 80,
child: Row(
children: [
Expanded(
child: IconButton(
icon: const Icon(Icons.abc),
onPressed: () {
setState(() {
tab = 0;
});
},
),
),
Expanded(
child: IconButton(
icon: const Icon(Icons.add_box),
onPressed: () {
setState(() {
tab = 1;
});
},
),
),
Expanded(
child: IconButton(
icon: const Icon(Icons.air),
onPressed: () {
setState(() {
tab = 2;
});
},
),
)
],
),
),
),
]),
),
)
Painter code:
class TabPainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = Colors.white
..style = PaintingStyle.fill;
Path path = Path()
..moveTo(0, size.height)
..quadraticBezierTo(
size.width * 0.2, size.height, size.width * 0.15, size.height * 0.5)
..quadraticBezierTo(size.width * 0.1, 0, size.width * 0.3, 0)
..lineTo(size.width * 0.7, 0)
..quadraticBezierTo(
size.width * 0.9, 0, size.width * 0.85, size.height * 0.5)
..quadraticBezierTo(
size.width * 0.8, size.height, size.width * 1.1, size.height)
..close();
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
tab is just a integer variable
Output
Related
I am currently developing my first flutter-application and I need some help with my onboarding screen.
The top part has a Lottiefile asset in a container. The bottom part has some Buttons.
Is it possible to set the size of the container with the Lottiefile asset in it depending of the size of the bottom part? I do not want to have a scroll view, so everything should fit it one screen. The Lottiefile asset should fill the space between the top and the beginning of the bottom part. Is there any possibility to set the size depending of the width and height of the free space?
I tried to set height & width to double.infinity but that crashed my app.
Here's the code:
class OnBoardingPage extends StatelessWidget {
const OnBoardingPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
elevation: 0,
backgroundColor: AppColor.statusbarColor,
),
backgroundColor: AppColor.statusbarColor,
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // <-- spaceBetween
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: size.width * 0.08),
child: Column(
children: [
SizedBox(
height: size.height * 0.03,
),
Container(
width: double.infinity,
child: Lottie.asset('assets/images/files.json',
fit: BoxFit.cover, repeat: false),
),
],
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: size.width * 0.08),
child: Column(
children: [
SizedBox(
height: size.height * 0.05,
),
Container(
height: size.height * 0.012,
width: size.width * 0.14,
decoration: BoxDecoration(
color: AppColor.textColor,
borderRadius: BorderRadius.circular(15)),
),
SizedBox(
height: size.height * 0.03,
),
AppText(
title: "...",
color: AppColor.textColor,
size: size.height * 0.024,
),
SizedBox(
height: size.height * 0.015,
),
AppText(
title:
"...",
textAlign: TextAlign.center,
color: AppColor.textColor,
size: size.height * 0.018,
),
SizedBox(
height: size.height * 0.05,
),
AppButton(
buttonName: "Register",
buttonColor: AppColor.buttonColor,
textColor: AppColor.buttonTextColor,
onTap: () {
Get.to(const SignUp());
},
buttonRadius: BorderRadius.circular(15),
buttonWidth: size.width,
fontWeight: FontWeight.w500,
buttonHeight: size.height * 0.065,
),
SizedBox(
height: size.height * 0.02,
),
AppButton(
buttonName: "Login",
buttonColor: AppColor.buttonColor,
textColor: AppColor.buttonTextColor,
onTap: () {
Get.to(const LoginScreen());
},
buttonRadius: BorderRadius.circular(15),
buttonWidth: size.width,
fontWeight: FontWeight.w500,
buttonHeight: size.height * 0.065,
),
SizedBox(
height: size.height * 0.02,
),
InkWell(
onTap: () {
Get.to(const Guest());
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AppText(
title: "Continue as a Guest (...)",
color: AppColor.primaryColor,
size: size.height * 0.02,
),
SizedBox(
height: size.height * 0.014,
),
],
),
),
SizedBox(
height: size.height * 0.05,
),
],
),
),
],
));
}
}
I hope somebody is can help me with that problem. Thank you very much.
Did you try wrapping your Column or Container in an Expanded widget?
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,
),
)
In my page I have a gridview. In gridview items I use ClipPath. The problem is here. The path that I shows is on top and it is not possible to change it's position into the bottom:
#override
Widget build(BuildContext context) {
ScreenUtil.init(context,
designSize: Size(360, 640), allowFontScaling: true);
return Scaffold(
body: Stack(
children: [
Padding(
padding: Dimention.mainChartsOverallLRPadding.copyWith(top: 100.h),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: GridView.count(
padding: EdgeInsets.zero,
physics: ScrollPhysics(),
crossAxisCount: 2,
childAspectRatio: 160 / 144,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
children: gridItems
.map(
(item) => Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(8),
),
child: Stack(
children: [
ClipPath(
clipper: ChartDegreeArtWidget(),
child: Container(
decoration: BoxDecoration(
color: item.color.toColor(),
borderRadius: BorderRadius.circular(8),
),
),
)
],
),
),
)
.toList(),
shrinkWrap: true,
),
),
],
),
),
],
),
);
It's result:
How can I change curve path position into bottom of container ? Align is not working
here is my result, I think so the problem is in the ChartDegreeArtWidget, use the code below
class ChartDegreeArtWidget extends CustomClipper<Path> {
#override
Path getClip(Size size) {
var path = Path();
path.moveTo(0, size.height * 0.55);
path.quadraticBezierTo(size.width * 0.25, size.height * 0.3, size.width * 0.6, size.height * 0.6);
path.quadraticBezierTo(size.width * 0.85, size.height * 0.8, size.width * 1.0, size.height * 0.6);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
[![want to place fb, twitter icons inside rectangle][1]][1]
[1]: https://i.stack.imgur.com/psDqQ.jpg
class _Frame1State extends State<Frame1> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(children: [
Container(
width: double.infinity,
height: containerHeight,
decoration: BoxDecoration(color: kcolorframe1BgColor),
),
Positioned(
top: 10,
right: 10,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
fit: BoxFit.fill, image: AssetImage(kimageLoveImage))),
)),
Positioned(
bottom: 2,
height: bottomBaseHeight,
width: bottomBaseWidth,
child: CustomPaint(
size: Size.infinite,
painter: PathPainterLine(),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
icon: Icon(
FontAwesomeIcons.facebook,
),
),
IconButton(
icon: Icon(
FontAwesomeIcons.twitter,
),
),
.
.
.
}
class PathPainterLine extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
Path path = Path();
path.moveTo(0, 0);
path.lineTo(2 * size.width / 3, 0);
path.moveTo(0, 0);
path.addRRect(RRect.fromRectXY(
Rect.fromLTRB(2 * size.width / 3, -10, size.width, 10), 10, 10));
canvas.drawPath(path, paint);
}
}
How to use place row inside custompainter rectangle in flutter?
How to place row of icons inside custom-painter rectangle created, the child property of CustomPaint doesn't work as it shifts the Row to bottom,please help ?
Your PathPainterLine is painting outside of the Canvas:
1. Fix your PathPainterLine:
class PathPainterLine extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
Path path = Path();
path.moveTo(0, size.height / 2);
path.lineTo(2 * size.width / 3, size.height / 2);
path.addRRect(RRect.fromRectXY(
Rect.fromLTRB(2 * size.width / 3, 0, size.width, size.height), 10, 10));
canvas.drawPath(path, paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
2. Properly size and position your Row
child: CustomPaint(
painter: PathPainterLine(),
child: Align(
alignment: Alignment.centerRight,
child: Container(
padding: EdgeInsets.symmetric(horizontal: frameWidth / 50),
width: frameWidth / 3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.train, size: 16),
Icon(Icons.flight, size: 16),
],
),
),
),
),
Result
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?