Skip to content

Commit 7b88a8d

Browse files
committed
gfshimmer basic design added
1 parent 9001bef commit 7b88a8d

File tree

3 files changed

+227
-0
lines changed

3 files changed

+227
-0
lines changed

example/lib/main.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,29 @@ class _MyHomePageState extends State<MyHomePage>
226226
},
227227
),
228228

229+
GFShimmer(
230+
child: const Text(
231+
'Slide to unlock',
232+
style: TextStyle(
233+
fontSize: 48,
234+
fontWeight: FontWeight.w700
235+
),
236+
),
237+
// direction: ShimmerDirection.ltr,
238+
gradient: LinearGradient(
239+
begin: Alignment.topLeft,
240+
end: Alignment.bottomRight,
241+
colors: [
242+
Colors.red[900],
243+
Colors.red[600],
244+
Colors.red[400],
245+
Colors.red[100],
246+
],),
247+
// baseColor: Colors.teal,
248+
// highlightColor: Colors.tealAccent,
249+
loop: 3,
250+
),
251+
229252

230253
// GFRating(
231254
// value: _rating,
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter/rendering.dart';
3+
4+
enum GFShimmerDirection { ltr, rtl, ttb, btt }
5+
6+
@immutable
7+
class GFShimmer extends StatefulWidget {
8+
const GFShimmer({
9+
Key key,
10+
@required this.child,
11+
@required this.gradient,
12+
this.direction = GFShimmerDirection.ltr,
13+
this.period = const Duration(milliseconds: 1500),
14+
this.loop = 0,
15+
this.enabled = true,
16+
}) : super(key: key);
17+
18+
final Widget child;
19+
final Duration period;
20+
final GFShimmerDirection direction;
21+
final Gradient gradient;
22+
final int loop;
23+
final bool enabled;
24+
25+
GFShimmer.fromColors({
26+
Key key,
27+
@required this.child,
28+
@required Color baseColor,
29+
@required Color highlightColor,
30+
this.period = const Duration(milliseconds: 1500),
31+
this.direction = GFShimmerDirection.ltr,
32+
this.loop = 0,
33+
this.enabled = true,
34+
}) : gradient = LinearGradient(
35+
begin: Alignment.topLeft,
36+
end: Alignment.centerRight,
37+
colors: <Color>[
38+
baseColor,
39+
baseColor,
40+
highlightColor,
41+
baseColor,
42+
baseColor
43+
],
44+
stops: const <double>[
45+
0,
46+
0.35,
47+
0.5,
48+
0.65,
49+
1
50+
]),
51+
super(key: key);
52+
53+
@override
54+
_GFShimmerState createState() => _GFShimmerState();
55+
}
56+
57+
class _GFShimmerState extends State<GFShimmer> with SingleTickerProviderStateMixin {
58+
AnimationController _controller;
59+
int _count;
60+
61+
@override
62+
void initState() {
63+
super.initState();
64+
_count = 0;
65+
_controller = AnimationController(vsync: this, duration: widget.period)
66+
..addStatusListener((AnimationStatus status) {
67+
if (status != AnimationStatus.completed) {
68+
return;
69+
}
70+
_count++;
71+
if (widget.loop <= 0) {
72+
_controller.repeat();
73+
} else if (_count < widget.loop) {
74+
_controller.forward(from: 0);
75+
}
76+
});
77+
if (widget.enabled) {
78+
_controller.forward();
79+
}
80+
}
81+
82+
@override
83+
void didUpdateWidget(GFShimmer oldWidget) {
84+
if (widget.enabled) {
85+
_controller.forward();
86+
} else {
87+
_controller.stop();
88+
}
89+
super.didUpdateWidget(oldWidget);
90+
}
91+
92+
@override
93+
Widget build(BuildContext context) => AnimatedBuilder(
94+
animation: _controller,
95+
child: widget.child,
96+
builder: (BuildContext context, Widget child) => _GFShimmer(
97+
child: child,
98+
direction: widget.direction,
99+
gradient: widget.gradient,
100+
percent: _controller.value,
101+
enabled: widget.enabled,
102+
),
103+
);
104+
105+
106+
@override
107+
void dispose() {
108+
_controller.dispose();
109+
super.dispose();
110+
}
111+
}
112+
113+
@immutable
114+
class _GFShimmer extends SingleChildRenderObjectWidget {
115+
const _GFShimmer({
116+
Widget child,
117+
this.percent,
118+
this.direction,
119+
this.gradient,
120+
this.enabled,
121+
}) : super(child: child);
122+
123+
final double percent;
124+
final GFShimmerDirection direction;
125+
final Gradient gradient;
126+
final bool enabled;
127+
128+
@override
129+
_GFShimmerFilter createRenderObject(BuildContext context) => _GFShimmerFilter(percent, direction, gradient, enabled);
130+
131+
@override
132+
void updateRenderObject(BuildContext context, _GFShimmerFilter shimmer) {
133+
shimmer.percent = percent;
134+
shimmer.enabled = enabled;
135+
}
136+
}
137+
138+
class _GFShimmerFilter extends RenderProxyBox {
139+
140+
_GFShimmerFilter(this._percent, this._direction, this._gradient, this.enabled)
141+
: _gradientPaint = Paint()..blendMode = BlendMode.srcIn;
142+
143+
final Paint _clearPaint = Paint();
144+
final Paint _gradientPaint;
145+
final Gradient _gradient;
146+
final GFShimmerDirection _direction;
147+
bool enabled;
148+
double _percent;
149+
Rect _rect;
150+
151+
@override
152+
bool get alwaysNeedsCompositing => child != null;
153+
154+
set percent(double newValue) {
155+
if (newValue == _percent) {
156+
return;
157+
}
158+
_percent = newValue;
159+
markNeedsPaint();
160+
}
161+
162+
@override
163+
void paint(PaintingContext context, Offset offset) {
164+
if (child == null) {
165+
return;
166+
}
167+
assert(needsCompositing);
168+
169+
context.canvas.saveLayer(offset & child.size, _clearPaint);
170+
context.paintChild(child, offset);
171+
172+
final double width = child.size.width;
173+
final double height = child.size.height;
174+
Rect rect;
175+
double dx, dy;
176+
if (_direction == GFShimmerDirection.rtl) {
177+
dx = _offset(width, -width, _percent);
178+
dy = 0.0;
179+
rect = Rect.fromLTWH(offset.dx - width, offset.dy, 3 * width, height);
180+
} else if (_direction == GFShimmerDirection.ttb) {
181+
dx = 0.0;
182+
dy = _offset(-height, height, _percent);
183+
rect = Rect.fromLTWH(offset.dx, offset.dy - height, width, 3 * height);
184+
} else if (_direction == GFShimmerDirection.btt) {
185+
dx = 0.0;
186+
dy = _offset(height, -height, _percent);
187+
rect = Rect.fromLTWH(offset.dx, offset.dy - height, width, 3 * height);
188+
} else {
189+
dx = _offset(-width, width, _percent);
190+
dy = 0.0;
191+
rect = Rect.fromLTWH(offset.dx - width, offset.dy, 3 * width, height);
192+
}
193+
if (_rect != rect) {
194+
_gradientPaint.shader = _gradient.createShader(rect);
195+
_rect = rect;
196+
}
197+
context.canvas.translate(dx, dy);
198+
context.canvas.drawRect(rect, _gradientPaint);
199+
context.canvas.restore();
200+
}
201+
202+
double _offset(double start, double end, double percent) => start + (end - start) * percent;
203+
}

lib/getflutter.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export 'package:getflutter/components/toggle/gf_toggle.dart';
2828
export 'package:getflutter/components/typography/gf_typography.dart';
2929
export 'package:getflutter/components/rating/gf_rating.dart';
3030
export 'package:getflutter/components/slidable/gf_slidable.dart';
31+
export 'package:getflutter/components/shimmer/gf_shimmer.dart';
3132

3233
// exports shape, color, position, size, types
3334
export 'colors/gf_color.dart';

0 commit comments

Comments
 (0)