Skip to content

Commit 194d5a8

Browse files
committed
small fix in Graphics.
new demos: - Lungs animation. - Path chart stress test. - Expander Fab Menu.
1 parent 59f4171 commit 194d5a8

File tree

13 files changed

+691
-5
lines changed

13 files changed

+691
-5
lines changed
66.7 KB
Loading

example/assets/trigrid/cute_dog.png

64.7 KB
Loading

example/lib/demos/chart_mountain/scene/chart_scene.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import 'package:exampleGraphx/utils/utils.dart';
1+
import 'package:flutter/material.dart';
22
import 'package:graphx/graphx.dart';
33

44
import '../chart_data.dart';

example/lib/demos/demos.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export 'dna_3d/dna_3d.dart';
1212
export 'drawing_pad_bezier/drawing_pad_bezier.dart';
1313
export 'dripping_iv/dripping_iv.dart';
1414
export 'elastic_band/elastic_band.dart';
15+
export 'expander_fab_menu/expander_fab_menu.dart';
1516
export 'fb_reactions/fb_reactions.dart';
1617
export 'feeling_switch/feeling_switch.dart';
1718
export 'flower_gradient/flower_gradient.dart';
@@ -23,10 +24,12 @@ export 'heart_reaction/heart_reaction.dart';
2324
export 'isma_chart/isma_chart.dart';
2425
export 'jelly_thing/jelly_thing.dart';
2526
export 'lined_button/lined_button.dart';
27+
export 'lungs/lungs.dart';
2628
export 'mouse_repulsion/mouse_repulsion.dart';
2729
export 'murat_coffee/murat_coffee.dart';
2830
export 'nico_loading_indicator/nico_loading_indicator.dart';
2931
export 'nokia_snake/nokia_snake.dart';
32+
export 'path_chart_stress/path_chart_stress.dart';
3033
export 'pie_chart/pie_chart.dart';
3134
export 'pizza_box/pizza_box.dart';
3235
export 'raster_draw/raster_draw.dart';
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:graphx/graphx.dart';
3+
4+
class ExpanderFabMenu extends StatelessWidget {
5+
@override
6+
Widget build(BuildContext context) {
7+
return Theme(
8+
data: Theme.of(context).copyWith(
9+
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.red),
10+
),
11+
child: Scaffold(
12+
appBar: AppBar(
13+
title: Text(
14+
'Custom Animation',
15+
style: TextStyle(color: Colors.black),
16+
),
17+
backgroundColor: Colors.white,
18+
centerTitle: false,
19+
leading: IconButton(
20+
icon: Icon(
21+
Icons.arrow_back,
22+
color: Colors.black,
23+
),
24+
),
25+
),
26+
body: MyMenu(
27+
child: ListView.builder(
28+
itemBuilder: (_, idx) {
29+
return Card(
30+
child: Padding(
31+
padding: const EdgeInsets.all(16.0),
32+
child: Text('Item num $idx'),
33+
),
34+
elevation: 2,
35+
);
36+
},
37+
itemCount: 50,
38+
),
39+
),
40+
),
41+
);
42+
}
43+
}
44+
45+
class MyMenu extends StatefulWidget {
46+
final Widget child;
47+
48+
const MyMenu({Key key, this.child}) : super(key: key);
49+
50+
@override
51+
_MyMenuState createState() => _MyMenuState();
52+
}
53+
54+
class _MyMenuState extends State<MyMenu> with TickerProviderStateMixin {
55+
bool isOpen = false;
56+
57+
AnimationController anim;
58+
final GlobalKey mySuperKey = GlobalKey();
59+
final menuScene = MyCoolMenuScene();
60+
61+
@override
62+
void initState() {
63+
super.initState();
64+
final dur = Duration(seconds: 1);
65+
// anim = AnimationController(
66+
// vsync: this,
67+
// duration: dur,
68+
// );
69+
// anim.addListener(() {
70+
// setState(() {});
71+
// });
72+
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
73+
getPosition();
74+
});
75+
}
76+
77+
void getPosition() {
78+
var ro = mySuperKey.currentContext.findRenderObject() as RenderBox;
79+
var menuRO = context.findRenderObject() as RenderBox;
80+
var position = ro.localToGlobal(Offset.zero, ancestor: menuRO);
81+
menuScene.updatePosition(GRect.fromNative(position & ro.size));
82+
}
83+
84+
@override
85+
Widget build(BuildContext context) {
86+
final baseButton = IconButton(
87+
icon: Icon(Icons.android),
88+
onPressed: () {},
89+
);
90+
return SceneBuilderWidget(
91+
builder: () => SceneController(front: menuScene),
92+
child: Stack(
93+
children: [
94+
Container(
95+
// color: Colors.red,
96+
child: Column(
97+
children: [
98+
Expanded(child: widget.child),
99+
Container(
100+
height: 60,
101+
decoration: BoxDecoration(color: Colors.white, boxShadow: [
102+
BoxShadow(
103+
color: Colors.black38,
104+
blurRadius: 12,
105+
offset: Offset(0, -1),
106+
spreadRadius: 2)
107+
]),
108+
child: Row(
109+
mainAxisAlignment: MainAxisAlignment.spaceAround,
110+
children: [
111+
baseButton,
112+
baseButton,
113+
Container(
114+
width: 40,
115+
height: 40,
116+
color: Colors.transparent,
117+
key: mySuperKey,
118+
),
119+
// Visibility(
120+
// visible: !isOpen,
121+
// child: myFav(),
122+
// ),
123+
baseButton,
124+
baseButton,
125+
],
126+
),
127+
),
128+
],
129+
),
130+
),
131+
// buildMenu(),
132+
// buildAnimFab(),
133+
],
134+
),
135+
);
136+
}
137+
138+
// Widget buildAnimFab() {
139+
// print(isOpen);
140+
// print(anim.value);
141+
// print(pos);
142+
// if (!isOpen) {}
143+
// return Positioned(
144+
// top: pos.dy * (1 - anim.value),
145+
// left: pos.dx,
146+
// child: IconButton(
147+
// // key: mySuperKey,
148+
// icon: Icon(
149+
// Icons.accessibility,
150+
// color: Colors.red,
151+
// ),
152+
// // backgroundColor: Colors.white,
153+
// onPressed: () {
154+
// isOpen = !isOpen;
155+
// trace('pressed', isOpen);
156+
// if (isOpen) {
157+
// anim.forward();
158+
// } else {
159+
// anim.reverse();
160+
// }
161+
// },
162+
// ),
163+
// );
164+
// }
165+
}
166+
167+
class MyCoolMenuScene extends GSprite {
168+
MyButton button;
169+
170+
bool isOpen = false;
171+
172+
MyCoolMenuScene() {
173+
button = MyButton();
174+
}
175+
176+
GRect _position;
177+
double buttonY;
178+
GShape curtain;
179+
180+
void updatePosition(GRect position) {
181+
_position = position;
182+
button.x = position.x + position.width / 2;
183+
button.y = buttonY = position.y + position.height / 2;
184+
}
185+
186+
GSprite menuContainer;
187+
188+
@override
189+
void addedToStage() {
190+
super.addedToStage();
191+
curtain = GShape();
192+
addChild(curtain);
193+
194+
menuContainer = GSprite();
195+
addChild(menuContainer);
196+
_buildMenu();
197+
addChild(button);
198+
199+
button.onMouseClick.add((event) {
200+
isOpen = !isOpen;
201+
button.open(isOpen);
202+
showMenuNow();
203+
if (isOpen) {
204+
curtain.tween(
205+
duration: .3,
206+
alpha: 1,
207+
);
208+
button.tween(
209+
duration: .95,
210+
rotation: deg2rad(45 * 6.0),
211+
ease: GEase.easeInOutExpo,
212+
y: button.height / 2 + 80,
213+
// scale: 1.5,
214+
onUpdate: () {
215+
if (button.y > sh * .5) {
216+
twnCurtainY = button.y;
217+
_renderCurt();
218+
} else {
219+
_bounceCurtain();
220+
}
221+
},
222+
);
223+
224+
} else {
225+
curtain.tween(
226+
duration: .5,
227+
alpha: 0,
228+
);
229+
button.tween(
230+
duration: .75,
231+
rotation: deg2rad(0),
232+
ease: GEase.easeOutExpo,
233+
scale: 1,
234+
y: buttonY,
235+
// onUpdate: _updateButton,
236+
);
237+
}
238+
});
239+
}
240+
241+
double get sw => stage.stageWidth;
242+
243+
double get sh => stage.stageHeight;
244+
var twnCurtainY = 0.0;
245+
246+
bool bounceCurtain = false;
247+
248+
_bounceCurtain() {
249+
if (bounceCurtain) return;
250+
bounceCurtain = true;
251+
final myTween = twnCurtainY.twn;
252+
myTween.tween(
253+
sh,
254+
duration: 1,
255+
ease: GEase.easeOutQuad,
256+
onUpdate: () {
257+
twnCurtainY = myTween.value;
258+
_renderCurt();
259+
},
260+
onComplete: () {
261+
bounceCurtain = false;
262+
},
263+
);
264+
}
265+
266+
void _renderCurt() {
267+
final g = curtain.graphics;
268+
269+
g.clear();
270+
// g.lineStyle(2, Colors.black);
271+
g.beginFill(Colors.red);
272+
g.moveTo(0, sh);
273+
g.curveTo(button.x, sh, button.x, twnCurtainY);
274+
g.curveTo(button.x, sh, sw, sh);
275+
g.lineTo(sw, 0).lineTo(0, 0).closePath();
276+
}
277+
278+
List<GText> items = [];
279+
280+
void _buildMenu() {
281+
items = [];
282+
var list = ['Reminder', 'Camera', 'Attachment', 'Text Note'];
283+
for (var i = 0; i < list.length; ++i) {
284+
var itm = GText.build(
285+
text: list[i],
286+
color: Colors.white,
287+
fontSize: 20,
288+
doc: menuContainer,
289+
);
290+
itm.alignPivot();
291+
itm.alpha=0;
292+
itm.y = i * 34.0;
293+
items.add(itm);
294+
}
295+
menuContainer.alignPivot();
296+
menuContainer.setPosition(sw/2,sh/2);
297+
}
298+
299+
void showMenuNow() {
300+
var len = items.length ;
301+
for (var i = 0; i < items.length; ++i) {
302+
var itm = items[i];
303+
itm.y = i * 34.0;
304+
double ta = isOpen ? 1 : 0 ;
305+
if( isOpen ){
306+
itm.tween(duration: .45, delay: .25 + ((len-1)-i) * .09, alpha: ta);
307+
} else {
308+
itm.tween(duration: .12, delay: 0, alpha: 0, overwrite: 1);
309+
}
310+
}
311+
}
312+
}
313+
314+
class MyButton extends GSprite {
315+
GShape bg;
316+
GIcon icon;
317+
double radius = 20;
318+
319+
@override
320+
void addedToStage() {
321+
super.addedToStage();
322+
bg = GShape();
323+
addChild(bg);
324+
bg.graphics.beginFill(Colors.red).drawCircle(0, 0, radius).endFill();
325+
icon = GIcon(Icons.add);
326+
addChild(icon);
327+
icon.alignPivot();
328+
mouseChildren = false;
329+
useCursor = true;
330+
onMouseOver.add((event) {
331+
scale = sc * 1.2;
332+
});
333+
onMouseOut.add((event) {
334+
scale = sc * 1;
335+
});
336+
}
337+
338+
double sc = 1.0;
339+
340+
bool isOpen = false;
341+
342+
void open(bool isOpen) {
343+
this.isOpen = isOpen;
344+
// sc = isOpen ? 1.5:1.0;
345+
bg.colorize = isOpen ? Colors.white : Colors.red;
346+
icon.color = isOpen ? Colors.red : Colors.white;
347+
// bg.tween(
348+
// duration: .1,
349+
// colorize: isOpen ? Colors.white : Colors.red,
350+
// );
351+
// icon.tween(
352+
// duration: .1,
353+
// colorize: isOpen ? Colors.red : Colors.white,
354+
// );
355+
}
356+
}

example/lib/demos/fb_reactions/fb_reactions.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class InnerCardItem extends StatelessWidget {
8080
CircleAvatar(
8181
backgroundColor: Colors.grey.withOpacity(.3),
8282
radius: 24,
83-
foregroundImage: NetworkImage(data.profileImageUrl),
83+
/// dev channel
84+
// foregroundImage: NetworkImage(data.profileImageUrl),
8485
child: Text(data.username[0].toUpperCase()),
8586
),
8687
const SizedBox(width: 8),

0 commit comments

Comments
 (0)