Skip to content

Commit 62cbdac

Browse files
committed
Buat wave bottom navigation bar
1 parent efa9bf0 commit 62cbdac

File tree

6 files changed

+267
-105
lines changed

6 files changed

+267
-105
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import 'package:flutter/material.dart';
2+
3+
class WavyBottomNavigationBarClipper extends CustomClipper<Path> {
4+
@override
5+
Path getClip(Size size) {
6+
Path path = Path();
7+
8+
path.lineTo(0, 2);
9+
path.lineTo(10, 3);
10+
path.lineTo(15, 5);
11+
path.lineTo(20, 10);
12+
var firstControlPoint = Offset((size.width / 3.6) - 40, 60);
13+
var firstEndPoint = Offset(size.width / 3.6, 10);
14+
path.quadraticBezierTo(
15+
firstControlPoint.dx,
16+
firstControlPoint.dy,
17+
firstEndPoint.dx,
18+
firstEndPoint.dy,
19+
);
20+
path.lineTo(size.width / 3.6, 10);
21+
22+
var dxSecondEndPoint = size.width / 3;
23+
var secondControlPoint = Offset(dxSecondEndPoint + 5, -10);
24+
var secondEndPoint = Offset(dxSecondEndPoint + 25, 10);
25+
path.quadraticBezierTo(
26+
secondControlPoint.dx,
27+
secondControlPoint.dy,
28+
secondEndPoint.dx,
29+
secondEndPoint.dy,
30+
);
31+
path.lineTo(dxSecondEndPoint + 25, 10);
32+
33+
var dxThirdEndPoint = size.width - (size.width / 2.5);
34+
var thirdControlPoint = Offset(dxThirdEndPoint - 36, 60);
35+
var thirdEndPoint = Offset((size.width / 3) * 2 - 25, 10);
36+
path.quadraticBezierTo(
37+
thirdControlPoint.dx,
38+
thirdControlPoint.dy,
39+
thirdEndPoint.dx,
40+
thirdEndPoint.dy,
41+
);
42+
43+
var dxFourthEndPoint = (size.width / 3) * 2;
44+
var fourthControlPoint = Offset(dxFourthEndPoint + 5, -10);
45+
var fourthEndPoint = Offset(dxFourthEndPoint + 25, 10);
46+
path.quadraticBezierTo(
47+
fourthControlPoint.dx,
48+
fourthControlPoint.dy,
49+
fourthEndPoint.dx,
50+
fourthEndPoint.dy,
51+
);
52+
53+
var dxFifthEndPoint = size.width - ((size.width / 3.6) - 40);
54+
var fifthControlPoint = Offset(dxFifthEndPoint, 60);
55+
var fifthEndPoint = Offset(dxFifthEndPoint + 40, 10);
56+
path.quadraticBezierTo(
57+
fifthControlPoint.dx,
58+
fifthControlPoint.dy,
59+
fifthEndPoint.dx,
60+
fifthEndPoint.dy,
61+
);
62+
63+
path.lineTo(size.width - 20, 10);
64+
path.lineTo(size.width - 15, 5);
65+
path.lineTo(size.width - 10, 3);
66+
path.lineTo(size.width, 2);
67+
path.lineTo(size.width, size.height);
68+
path.lineTo(0, size.height);
69+
path.close();
70+
71+
return path;
72+
}
73+
74+
@override
75+
bool shouldReclip(CustomClipper<Path> oldClipper) {
76+
return true;
77+
}
78+
}

lib/clipper/wavy_image_clipper.dart

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import 'package:flutter/material.dart';
2+
3+
class WavyImageClipper extends CustomClipper<Path> {
4+
@override
5+
Path getClip(Size size) {
6+
Path path = Path();
7+
8+
path.lineTo(0, size.height - 200);
9+
var firstControlPoint = Offset(0, size.height - 160);
10+
var firstEndPoint = Offset(30, size.height - 150);
11+
path.quadraticBezierTo(
12+
firstControlPoint.dx,
13+
firstControlPoint.dy,
14+
firstEndPoint.dx,
15+
firstEndPoint.dy,
16+
);
17+
18+
path.lineTo(size.width - 30, size.height - 50);
19+
var secondControlPoint = Offset(size.width, size.height - 40);
20+
var secondEndPoint = Offset(size.width, size.height);
21+
path.quadraticBezierTo(
22+
secondControlPoint.dx,
23+
secondControlPoint.dy,
24+
secondEndPoint.dx,
25+
secondEndPoint.dy,
26+
);
27+
28+
path.lineTo(size.width, 200);
29+
var thirdControlPoint = Offset(size.width, 140);
30+
var thirdEndPoint = Offset(size.width - 30, 150);
31+
path.quadraticBezierTo(
32+
thirdControlPoint.dx,
33+
thirdControlPoint.dy,
34+
thirdEndPoint.dx,
35+
thirdControlPoint.dy,
36+
);
37+
38+
path.lineTo(30, 50);
39+
var fourthControlPoint = Offset(0, 40);
40+
var fourthEndPoint = Offset(0, 0);
41+
path.quadraticBezierTo(
42+
fourthControlPoint.dx,
43+
fourthControlPoint.dy,
44+
fourthEndPoint.dx,
45+
fourthEndPoint.dy,
46+
);
47+
48+
path.close();
49+
return path;
50+
}
51+
52+
@override
53+
bool shouldReclip(CustomClipper<Path> oldClipper) {
54+
return true;
55+
}
56+
}

lib/main.dart

Lines changed: 68 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import 'dart:ui';
22

33
import 'package:flutter/material.dart';
4+
import 'package:flutter_meditation_app/wavy/wavy_bottom_navigation_bar.dart';
5+
import 'package:flutter_meditation_app/wavy/wavy_image.dart';
6+
import 'package:flutter_meditation_app/widgets/container_black.dart';
47
import 'package:flutter_screenutil/flutter_screenutil.dart';
58

69
void main() => runApp(MyApp());
@@ -20,8 +23,6 @@ class MyHomePage extends StatelessWidget {
2023
ScreenUtil.init(context);
2124
MediaQueryData mediaQueryData = MediaQuery.of(context);
2225
double heightScreen = mediaQueryData.size.height;
23-
double paddingTop = mediaQueryData.padding.top;
24-
double paddingBottom = mediaQueryData.padding.bottom;
2526
return Scaffold(
2627
body: Container(
2728
width: double.infinity,
@@ -63,6 +64,62 @@ class MyHomePage extends StatelessWidget {
6364
),
6465
),
6566
_buildWidgetColumnText(),
67+
Align(
68+
alignment: Alignment.bottomCenter,
69+
child: WavyBottomNavigationBar(),
70+
),
71+
Align(
72+
alignment: Alignment.bottomCenter,
73+
child: Padding(
74+
padding: EdgeInsets.only(bottom: 100.w),
75+
child: Row(
76+
mainAxisAlignment: MainAxisAlignment.spaceAround,
77+
children: <Widget>[
78+
Container(
79+
decoration: BoxDecoration(
80+
color: Colors.white.withOpacity(0.1),
81+
shape: BoxShape.circle,
82+
),
83+
width: 150.w,
84+
height: 150.w,
85+
child: Icon(
86+
Icons.bubble_chart,
87+
color: Colors.white.withOpacity(0.5),
88+
size: ScreenUtil().setWidth(96),
89+
),
90+
),
91+
Container(
92+
decoration: BoxDecoration(
93+
color: Colors.white,
94+
shape: BoxShape.circle,
95+
border: Border.all(
96+
color: Colors.grey[800],
97+
width: 2,
98+
),
99+
),
100+
width: 150.w,
101+
height: 150.w,
102+
child: Icon(
103+
Icons.image,
104+
color: Colors.grey[900],
105+
),
106+
),
107+
Container(
108+
decoration: BoxDecoration(
109+
color: Colors.white.withOpacity(0.1),
110+
shape: BoxShape.circle,
111+
),
112+
width: 150.w,
113+
height: 150.w,
114+
child: Icon(
115+
Icons.brightness_3,
116+
color: Colors.white.withOpacity(0.5),
117+
),
118+
),
119+
],
120+
),
121+
),
122+
),
66123
],
67124
),
68125
),
@@ -92,12 +149,15 @@ class MyHomePage extends StatelessWidget {
92149
),
93150
),
94151
Expanded(
95-
child: Column(
96-
mainAxisAlignment: MainAxisAlignment.center,
97-
children: <Widget>[
98-
_buildWidgetTitle('Calm'),
99-
_buildWidgetSubtitle('Slow down and relax'),
100-
],
152+
child: Padding(
153+
padding: EdgeInsets.only(bottom: 200.w),
154+
child: Column(
155+
mainAxisAlignment: MainAxisAlignment.center,
156+
children: <Widget>[
157+
_buildWidgetTitle('Calm'),
158+
_buildWidgetSubtitle('Slow down and relax'),
159+
],
160+
),
101161
),
102162
),
103163
],
@@ -128,100 +188,3 @@ class MyHomePage extends StatelessWidget {
128188
);
129189
}
130190
}
131-
132-
class WavyImage extends StatelessWidget {
133-
final String img;
134-
135-
WavyImage(this.img);
136-
137-
@override
138-
Widget build(BuildContext context) {
139-
return ClipPath(
140-
child: Stack(
141-
children: <Widget>[
142-
Image.asset(
143-
img,
144-
fit: BoxFit.cover,
145-
height: 1150.w,
146-
),
147-
ContainerBlack(
148-
heightScreen: 1150.w,
149-
),
150-
],
151-
),
152-
clipper: WaveClipper(),
153-
);
154-
}
155-
}
156-
157-
class WaveClipper extends CustomClipper<Path> {
158-
@override
159-
Path getClip(Size size) {
160-
Path path = Path();
161-
162-
path.lineTo(0, size.height - 200);
163-
var firstControlPoint = Offset(0, size.height - 160);
164-
var firstEndPoint = Offset(30, size.height - 150);
165-
path.quadraticBezierTo(
166-
firstControlPoint.dx,
167-
firstControlPoint.dy,
168-
firstEndPoint.dx,
169-
firstEndPoint.dy,
170-
);
171-
172-
path.lineTo(size.width - 30, size.height - 50);
173-
var secondControlPoint = Offset(size.width, size.height - 40);
174-
var secondEndPoint = Offset(size.width, size.height);
175-
path.quadraticBezierTo(
176-
secondControlPoint.dx,
177-
secondControlPoint.dy,
178-
secondEndPoint.dx,
179-
secondEndPoint.dy,
180-
);
181-
182-
path.lineTo(size.width, 200);
183-
var thirdControlPoint = Offset(size.width, 140);
184-
var thirdEndPoint = Offset(size.width - 30, 150);
185-
path.quadraticBezierTo(
186-
thirdControlPoint.dx,
187-
thirdControlPoint.dy,
188-
thirdEndPoint.dx,
189-
thirdControlPoint.dy,
190-
);
191-
192-
path.lineTo(30, 50);
193-
var fourthControlPoint = Offset(0, 40);
194-
var fourthEndPoint = Offset(0, 0);
195-
path.quadraticBezierTo(
196-
fourthControlPoint.dx,
197-
fourthControlPoint.dy,
198-
fourthEndPoint.dx,
199-
fourthEndPoint.dy,
200-
);
201-
202-
path.close();
203-
return path;
204-
}
205-
206-
@override
207-
bool shouldReclip(CustomClipper<Path> oldClipper) {
208-
return true;
209-
}
210-
}
211-
212-
class ContainerBlack extends StatelessWidget {
213-
const ContainerBlack({
214-
Key key,
215-
@required this.heightScreen,
216-
}) : super(key: key);
217-
218-
final double heightScreen;
219-
220-
@override
221-
Widget build(BuildContext context) {
222-
return Container(
223-
height: heightScreen,
224-
color: Colors.black.withOpacity(0.5),
225-
);
226-
}
227-
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_meditation_app/clipper/wavy_bottom_navigation_bar_clipper.dart';
3+
import 'package:flutter_screenutil/flutter_screenutil.dart';
4+
5+
class WavyBottomNavigationBar extends StatelessWidget {
6+
@override
7+
Widget build(BuildContext context) {
8+
ScreenUtil.init(context);
9+
return ClipPath(
10+
child: Container(
11+
color: Colors.white,
12+
height: 180.w,
13+
),
14+
clipper: WavyBottomNavigationBarClipper(),
15+
);
16+
}
17+
}

lib/wavy/wavy_image.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_meditation_app/clipper/wavy_image_clipper.dart';
3+
import 'package:flutter_meditation_app/widgets/container_black.dart';
4+
import 'package:flutter_screenutil/flutter_screenutil.dart';
5+
6+
class WavyImage extends StatelessWidget {
7+
final String img;
8+
9+
WavyImage(this.img);
10+
11+
@override
12+
Widget build(BuildContext context) {
13+
ScreenUtil.init(context);
14+
return ClipPath(
15+
child: Stack(
16+
children: <Widget>[
17+
Image.asset(
18+
img,
19+
fit: BoxFit.cover,
20+
height: 1150.w,
21+
),
22+
ContainerBlack(
23+
heightScreen: 1150.w,
24+
),
25+
],
26+
),
27+
clipper: WavyImageClipper(),
28+
);
29+
}
30+
}

0 commit comments

Comments
 (0)